@llui/lexical-loro 0.1.0

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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +262 -0
  3. package/dist/agent-write.d.ts +123 -0
  4. package/dist/agent-write.d.ts.map +1 -0
  5. package/dist/agent-write.js +499 -0
  6. package/dist/agent-write.js.map +1 -0
  7. package/dist/binding.d.ts +122 -0
  8. package/dist/binding.d.ts.map +1 -0
  9. package/dist/binding.js +114 -0
  10. package/dist/binding.js.map +1 -0
  11. package/dist/index.d.ts +69 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +69 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/mapping.d.ts +115 -0
  16. package/dist/mapping.d.ts.map +1 -0
  17. package/dist/mapping.js +181 -0
  18. package/dist/mapping.js.map +1 -0
  19. package/dist/order.d.ts +124 -0
  20. package/dist/order.d.ts.map +1 -0
  21. package/dist/order.js +187 -0
  22. package/dist/order.js.map +1 -0
  23. package/dist/schema.d.ts +343 -0
  24. package/dist/schema.d.ts.map +1 -0
  25. package/dist/schema.js +363 -0
  26. package/dist/schema.js.map +1 -0
  27. package/dist/seed.d.ts +72 -0
  28. package/dist/seed.d.ts.map +1 -0
  29. package/dist/seed.js +72 -0
  30. package/dist/seed.js.map +1 -0
  31. package/dist/text.d.ts +167 -0
  32. package/dist/text.d.ts.map +1 -0
  33. package/dist/text.js +289 -0
  34. package/dist/text.js.map +1 -0
  35. package/dist/to-lexical.d.ts +119 -0
  36. package/dist/to-lexical.d.ts.map +1 -0
  37. package/dist/to-lexical.js +636 -0
  38. package/dist/to-lexical.js.map +1 -0
  39. package/dist/to-loro.d.ts +154 -0
  40. package/dist/to-loro.d.ts.map +1 -0
  41. package/dist/to-loro.js +718 -0
  42. package/dist/to-loro.js.map +1 -0
  43. package/dist/undo.d.ts +94 -0
  44. package/dist/undo.d.ts.map +1 -0
  45. package/dist/undo.js +200 -0
  46. package/dist/undo.js.map +1 -0
  47. package/package.json +64 -0
  48. package/src/agent-write.ts +613 -0
  49. package/src/binding.ts +185 -0
  50. package/src/index.ts +176 -0
  51. package/src/mapping.ts +206 -0
  52. package/src/order.ts +205 -0
  53. package/src/schema.ts +509 -0
  54. package/src/seed.ts +112 -0
  55. package/src/text.ts +357 -0
  56. package/src/to-lexical.ts +792 -0
  57. package/src/to-loro.ts +914 -0
  58. package/src/undo.ts +269 -0
@@ -0,0 +1,636 @@
1
+ /**
2
+ * Inbound sync: the Loro mirror → a Lexical `EditorState`.
3
+ *
4
+ * ── The one thing this must not do ─────────────────────────────────────────
5
+ *
6
+ * loro-prosemirror's inbound path replaces the whole document on every remote
7
+ * event (`sync-plugin.ts`). ProseMirror tolerates that. LEXICAL CANNOT: its
8
+ * `NodeKey` is a bare counter (`LexicalUtils.ts`: `'' + keyCounter++`), so a
9
+ * rebuild mints a fresh key for every node, which tears down all DOM, destroys
10
+ * the selection and IME composition, and — decisively for this stack — destroys
11
+ * and remounts EVERY `LLuiDecoratorNode`, because `packages/lexical/decorator.ts`
12
+ * disposes the mounted LLui sub-app on the 'destroyed' mutation.
13
+ *
14
+ * So this module is a PERSISTENT MIRROR: it resolves each remote change to an
15
+ * existing `NodeKey` through the registry in `mapping.ts` and MUTATES THAT NODE
16
+ * IN PLACE. Nodes nothing touched are never written, so their keys — and
17
+ * therefore their DOM, their mounts, and any selection inside them — survive by
18
+ * construction. That is the model `@lexical/yjs`'s `SyncEditorStates.ts` uses,
19
+ * and it is the only one that works here.
20
+ *
21
+ * ── Why it reconciles from STATE, not from the deltas ──────────────────────
22
+ *
23
+ * The events say WHERE the document changed; this module then reconciles those
24
+ * containers against Loro's CURRENT state rather than replaying each delta. Four
25
+ * reasons, all learned from the event shapes loro-crdt actually emits:
26
+ *
27
+ * 1. A batch that creates a subtree emits the parent's list insert AND a
28
+ * separate event for every descendant container. Replaying all of them
29
+ * double-applies; reconciling from state is idempotent, so the duplicate
30
+ * descriptions of one change collapse to one reconciliation.
31
+ * 2. A `LoroMovableList#move` arrives as an insert plus a delete carrying the
32
+ * SAME `ContainerID`. Reconciling by identity recognises that as a move —
33
+ * the whole point of the movable-list schema — where a delta replay would
34
+ * see a delete and rebuild the subtree.
35
+ * 3. A map deletion is reported as an `undefined` value in `MapDiff.updated`,
36
+ * which is indistinguishable from an absent key in most JS handling. Reading
37
+ * the map is unambiguous.
38
+ * 4. It is the mirror image of `to-loro.ts`, so both directions share one
39
+ * notion of "these two trees agree" (`text.ts`'s normalized runs) and cannot
40
+ * drift apart in their idea of what a difference is.
41
+ *
42
+ * The events are therefore used as a DIRTY SET, exactly as `to-loro.ts` uses
43
+ * Lexical's `dirtyElements`/`dirtyLeaves`: every element on the path from the
44
+ * root to a changed container is marked, and the walk descends only into marked
45
+ * children. A remote keystroke costs O(tree depth), not O(document).
46
+ *
47
+ * ── Selection ──────────────────────────────────────────────────────────────
48
+ *
49
+ * Untouched nodes keep their keys, so a caret outside the changed run needs no
50
+ * help at all. Only the case where a remote change lands INSIDE the exact text
51
+ * run holding the caret needs work: there the caret's offset is transformed
52
+ * through the same single-region diff used to update the run (a caret at or
53
+ * before the edit point does not move; one after it shifts by
54
+ * `insert.length - remove`; one inside a deleted span clamps to the edit point).
55
+ * That is deliberately narrow — reaching for cursors more broadly would mean
56
+ * writing selection on every remote event, which is its own source of jitter.
57
+ */
58
+ import { $createTextNode, $getRoot, $getSelection, $isElementNode, $isRangeSelection, $isTextNode, $parseSerializedNode, $setSelection, COLLABORATION_TAG, SKIP_SCROLL_INTO_VIEW_TAG, } from 'lexical';
59
+ import { LoroMap, } from 'loro-crdt';
60
+ import { ContainerNodeMap } from './mapping.js';
61
+ import { KEY_TYPE, containerId, containerIsLive, elementProps, elementType, isTextContainer, orderedChildren, } from './schema.js';
62
+ import { diffTextWithCursor, normalizeRuns, runsFromText, runsText } from './text.js';
63
+ // ---------------------------------------------------------------------------
64
+ // Public surface
65
+ // ---------------------------------------------------------------------------
66
+ /**
67
+ * Tags stamped on every inbound writeback.
68
+ *
69
+ * `COLLABORATION_TAG` is echo layer (b): `to-loro.ts` skips updates carrying it,
70
+ * so our own writeback cannot bounce back into the shared document.
71
+ * `SKIP_SCROLL_INTO_VIEW_TAG` stops a peer's edit from yanking the local
72
+ * viewport.
73
+ *
74
+ * `PROGRAMMATIC_TAG` is deliberately ABSENT and must stay that way — echo layer
75
+ * (c). `packages/lexical/src/foreign.ts` treats that tag as "the host pushed new
76
+ * content: cancel pending outbound work and rebase", so a remote writeback
77
+ * carrying it would silently cancel the local user's in-flight debounced
78
+ * `onChange` and the host's persistence would go dark whenever a peer types.
79
+ */
80
+ export const INBOUND_TAGS = [COLLABORATION_TAG, SKIP_SCROLL_INTO_VIEW_TAG];
81
+ /**
82
+ * Apply one Loro event batch to the editor.
83
+ *
84
+ * @returns whether anything was applied. `false` means the batch was an echo of
85
+ * our own write, or described no change the editor could see.
86
+ */
87
+ export function applyLoroToLexical(target, batch) {
88
+ // ── Echo layer (a) ──────────────────────────────────────────────────────
89
+ // A local batch is this peer's own outbound write completing its commit. Our
90
+ // outbound listener already produced it FROM the editor; feeding it back would
91
+ // re-enter `editor.update` from inside a Lexical update listener.
92
+ if (batch.by === 'local') {
93
+ const origins = target.localOrigins ?? [];
94
+ if (batch.origin === undefined || !origins.includes(batch.origin))
95
+ return false;
96
+ }
97
+ if (batch.events.length === 0)
98
+ return false;
99
+ const dirty = collectDirtyElements(target.doc, containerId(target.root), batch.events);
100
+ return $applyReconciliation(target, dirty);
101
+ }
102
+ /**
103
+ * Reconcile the ENTIRE shared document into the editor, with no dirty gate.
104
+ *
105
+ * Used at boot by a peer adopting a document it has no event history for (see
106
+ * `seed.ts`), and as the fallback whenever an event's container ancestry cannot
107
+ * be resolved. Full-fidelity and identity-preserving: adopting a document the
108
+ * editor already matches writes nothing and churns no NodeKeys.
109
+ */
110
+ export function adoptLoroDocument(target) {
111
+ return $applyReconciliation(target, null);
112
+ }
113
+ // ---------------------------------------------------------------------------
114
+ // The dirty set
115
+ // ---------------------------------------------------------------------------
116
+ /**
117
+ * Every element container on the path from the root to a container this batch
118
+ * touched — the inbound analogue of Lexical's `dirtyElements`.
119
+ *
120
+ * The walk goes UP from each event target via `parent()`, so it needs no path
121
+ * arithmetic and cannot be confused by indices that shifted within the batch.
122
+ *
123
+ * ── The fail-safe, and why it must be exactly this one ─────────────────────
124
+ *
125
+ * The gate is only sound if the editor already agreed with the document before
126
+ * the batch: a child that is not marked is left ALONE, so a single event whose
127
+ * location we resolve too narrowly leaves that subtree permanently stale, and
128
+ * nothing later repairs it (no future batch will mention it either). A narrowed
129
+ * dirty set is therefore not a small error — it is silent, unrecoverable
130
+ * divergence.
131
+ *
132
+ * So anything less than a walk that terminates at the ROOT WE MIRROR returns
133
+ * `null`, which drops the gate and falls back to a full structural pass —
134
+ * correct regardless of provenance, at the cost of one O(document) walk. An
135
+ * earlier version skipped events whose target reported `isDeleted()` instead,
136
+ * and a randomized three-peer test caught it: a container one peer deletes and
137
+ * another concurrently MOVES is resurrected by the merge, but reports itself
138
+ * deleted to the peer that removed it, so its events were dropped and that
139
+ * peer's editor silently stopped tracking the run for the rest of the session.
140
+ */
141
+ function collectDirtyElements(doc, rootId, events) {
142
+ const dirty = new Set();
143
+ for (const event of events) {
144
+ let cursor = doc.getContainerById(event.target);
145
+ let reached = false;
146
+ while (cursor !== undefined) {
147
+ // An element map is the only container carrying `type`; `props` maps and
148
+ // `children` lists are addressed through the element that owns them.
149
+ if (cursor instanceof LoroMap && cursor.get(KEY_TYPE) !== undefined)
150
+ dirty.add(cursor.id);
151
+ if (cursor.id === rootId)
152
+ reached = true;
153
+ cursor = cursor.parent();
154
+ }
155
+ if (!reached)
156
+ return null;
157
+ }
158
+ return dirty;
159
+ }
160
+ function $applyReconciliation(target, dirty) {
161
+ const context = {
162
+ doc: target.doc,
163
+ mapping: target.mapping,
164
+ dirty,
165
+ points: [],
166
+ changed: false,
167
+ removed: false,
168
+ };
169
+ target.editor.update(() => {
170
+ capturePoints(context);
171
+ const root = $getRoot();
172
+ context.mapping.link(containerId(target.root), root.getKey());
173
+ $applyProps(target.root, root, context);
174
+ $reconcileChildren(target.root, root, context);
175
+ $restorePoints(context);
176
+ }, {
177
+ tag: [...INBOUND_TAGS],
178
+ skipTransforms: true,
179
+ // REQUIRED. Lexical merges and splits adjacent TextNodes behind our back
180
+ // and reports it via `normalizedNodes`; without a synchronous flush the
181
+ // ContainerID ↔ NodeKey mapping drifts and the document corrupts.
182
+ discrete: true,
183
+ });
184
+ if (context.removed) {
185
+ const nodeMap = target.editor.getEditorState()._nodeMap;
186
+ target.mapping.sweep({
187
+ hasContainer: (id) => containerIsLive(target.doc, id),
188
+ hasNode: (key) => nodeMap.has(key),
189
+ });
190
+ }
191
+ return context.changed;
192
+ }
193
+ // ---------------------------------------------------------------------------
194
+ // Props
195
+ // ---------------------------------------------------------------------------
196
+ /**
197
+ * Apply an element container's props to an existing node, in place.
198
+ *
199
+ * `updateFromJSON` is Lexical's own in-place applier and the exact inverse of
200
+ * the `exportJSON` the outbound direction writes, so this stays generic over
201
+ * custom node types instead of poking private `__`-prefixed fields the way
202
+ * `@lexical/yjs` does.
203
+ *
204
+ * @returns `false` when the node's type does NOT implement `updateFromJSON`
205
+ * faithfully — the props did not take, so the caller must replace the node. That
206
+ * is detected by re-reading `exportJSON`, never assumed, because a node whose
207
+ * props silently fail to apply is a permanently-diverged document.
208
+ */
209
+ function $applyProps(container, node, context) {
210
+ const props = elementProps(container).toJSON();
211
+ if (!propsDiffer(props, node))
212
+ return true;
213
+ node.updateFromJSON(props);
214
+ context.changed = true;
215
+ if (!propsDiffer(props, node))
216
+ return true;
217
+ // Fall through to replacement, but say why: a node type reaching this point
218
+ // has an `exportJSON` its `updateFromJSON` cannot round-trip, which costs its
219
+ // subtree's NodeKeys (and any decorator mount in it) on every remote change.
220
+ console.error(`lexical-loro: '${node.getType()}'.updateFromJSON() does not apply every property its ` +
221
+ 'exportJSON() emits, so the node must be REPLACED on each remote change — which destroys ' +
222
+ 'its NodeKey, its DOM, and any mounted decorator sub-app. Implement updateFromJSON.');
223
+ return false;
224
+ }
225
+ /**
226
+ * Whether any prop the shared document holds differs from the node's own.
227
+ *
228
+ * Reads through `getLatest()`, which is load-bearing rather than defensive:
229
+ * `updateFromJSON` writes through `getWritable()`, which CLONES the node, so the
230
+ * reference the caller is holding is stale the moment the write lands. Comparing
231
+ * against it would report the update as having failed and trigger a needless —
232
+ * and mount-destroying — node replacement.
233
+ */
234
+ function propsDiffer(props, node) {
235
+ const current = node.getLatest().exportJSON();
236
+ for (const [key, value] of Object.entries(props)) {
237
+ if (!jsonEqual(current[key], value))
238
+ return true;
239
+ }
240
+ return false;
241
+ }
242
+ function jsonEqual(a, b) {
243
+ if (a === b)
244
+ return true;
245
+ if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object')
246
+ return false;
247
+ if (Array.isArray(a) !== Array.isArray(b))
248
+ return false;
249
+ if (Array.isArray(a) && Array.isArray(b)) {
250
+ return a.length === b.length && a.every((item, i) => jsonEqual(item, b[i]));
251
+ }
252
+ const left = a;
253
+ const right = b;
254
+ const keys = Object.keys(left);
255
+ if (keys.length !== Object.keys(right).length)
256
+ return false;
257
+ return keys.every((key) => key in right && jsonEqual(left[key], right[key]));
258
+ }
259
+ function groupChildren(node) {
260
+ const out = [];
261
+ let run = [];
262
+ const flush = () => {
263
+ if (run.length === 0)
264
+ return;
265
+ out.push({ kind: 'text', nodes: run, anchor: run[0].getKey() });
266
+ run = [];
267
+ };
268
+ for (const child of node.getChildren()) {
269
+ if ($isTextNode(child))
270
+ run.push(child);
271
+ else {
272
+ flush();
273
+ out.push({ kind: 'element', node: child, key: child.getKey() });
274
+ }
275
+ }
276
+ flush();
277
+ return out;
278
+ }
279
+ /**
280
+ * Reconcile a Lexical element's children against its container's child list.
281
+ *
282
+ * Matching is by IDENTITY through the registry: a container that already
283
+ * addresses a node reuses that node wherever it has moved to, which is what
284
+ * turns a remote reorder — one `pos` register write — into a Lexical reorder
285
+ * rather than a rebuild. Text runs additionally fall back to ordinal matching
286
+ * among the text
287
+ * children (mirroring the outbound direction), so a run whose anchor Lexical
288
+ * normalized away still finds its nodes instead of recreating them.
289
+ */
290
+ function $reconcileChildren(container, node, context) {
291
+ const desired = liveChildren(container);
292
+ const groups = groupChildren(node);
293
+ const claimed = new Set();
294
+ const byKey = new Map();
295
+ for (const group of groups) {
296
+ byKey.set(group.kind === 'text' ? group.anchor : group.key, group);
297
+ }
298
+ const textGroups = groups.filter((group) => group.kind === 'text');
299
+ let nextText = 0;
300
+ const matched = desired.map((child) => {
301
+ const key = context.mapping.nodeKey(containerId(child));
302
+ const found = key === undefined ? undefined : byKey.get(key);
303
+ if (found !== undefined && !claimed.has(found)) {
304
+ // A container whose node changed KIND (text ⇄ element) cannot be reused.
305
+ if (isTextContainer(child) === (found.kind === 'text')) {
306
+ claimed.add(found);
307
+ return found;
308
+ }
309
+ }
310
+ if (!isTextContainer(child))
311
+ return undefined;
312
+ while (nextText < textGroups.length && claimed.has(textGroups[nextText]))
313
+ nextText++;
314
+ const ordinal = textGroups[nextText];
315
+ if (ordinal === undefined)
316
+ return undefined;
317
+ nextText++;
318
+ claimed.add(ordinal);
319
+ return ordinal;
320
+ });
321
+ // 1. Build (or update in place) the node list this element should hold.
322
+ const ordered = [];
323
+ for (let i = 0; i < desired.length; i++) {
324
+ const child = desired[i];
325
+ const group = matched[i];
326
+ if (isTextContainer(child)) {
327
+ const existing = group !== undefined && group.kind === 'text' ? group.nodes : [];
328
+ const nodes = $reconcileTextRun(child, existing, context);
329
+ const id = containerId(child);
330
+ if (nodes.length === 0)
331
+ context.mapping.unlinkContainer(id);
332
+ else
333
+ context.mapping.link(id, nodes[0].getKey());
334
+ ordered.push(...nodes);
335
+ continue;
336
+ }
337
+ const existing = group !== undefined && group.kind === 'element' ? group.node : undefined;
338
+ ordered.push($reconcileElementChild(child, existing, context));
339
+ }
340
+ // 2. Remove whatever is no longer wanted. `preserveEmptyParent` is TRUE:
341
+ // Lexical's default removes a parent that this leaves empty, which would
342
+ // delete a block the shared document still holds.
343
+ const keep = new Set(ordered.map((child) => child.getKey()));
344
+ for (const group of groups) {
345
+ const nodes = group.kind === 'text' ? group.nodes : [group.node];
346
+ for (const child of nodes) {
347
+ if (keep.has(child.getKey()))
348
+ continue;
349
+ const id = context.mapping.containerId(child.getKey());
350
+ if (id !== undefined)
351
+ context.mapping.unlinkNode(child.getKey());
352
+ child.remove(true);
353
+ context.changed = true;
354
+ context.removed = true;
355
+ }
356
+ }
357
+ // 3. Place everything in order. Lexical's insert helpers MOVE an
358
+ // already-attached node without minting a new key, so a reorder here costs
359
+ // no identity — which is the whole point of the movable-list schema.
360
+ let previous = null;
361
+ for (const child of ordered) {
362
+ const parent = child.getParent();
363
+ const attached = parent !== null && parent.is(node);
364
+ const actual = attached ? child.getPreviousSibling() : undefined;
365
+ const inPlace = attached && ((actual === null && previous === null) || (actual?.is(previous) ?? false));
366
+ if (!inPlace) {
367
+ if (previous === null) {
368
+ const first = node.getFirstChild();
369
+ if (first === null)
370
+ node.append(child);
371
+ else
372
+ first.insertBefore(child, false);
373
+ }
374
+ else {
375
+ previous.insertAfter(child, false);
376
+ }
377
+ context.changed = true;
378
+ }
379
+ previous = child;
380
+ }
381
+ }
382
+ /**
383
+ * Reconcile one element child: update it in place when it is the same node, or
384
+ * build a fresh subtree when there is nothing reusable.
385
+ */
386
+ function $reconcileElementChild(container, existing, context) {
387
+ const id = containerId(container);
388
+ if (existing !== undefined && existing.getType() === elementType(container)) {
389
+ // Not dirty ⇒ nothing under this container changed, so do not descend.
390
+ if (context.dirty !== null && !context.dirty.has(id)) {
391
+ context.mapping.link(id, existing.getKey());
392
+ return existing;
393
+ }
394
+ if ($applyProps(container, existing, context)) {
395
+ context.mapping.link(id, existing.getKey());
396
+ if ($isElementNode(existing))
397
+ $reconcileChildren(container, existing, context);
398
+ return existing;
399
+ }
400
+ // Props could not be applied in place; fall through and rebuild.
401
+ }
402
+ context.changed = true;
403
+ return $buildNode(container, context);
404
+ }
405
+ /**
406
+ * Build a fresh Lexical subtree from a container the registry cannot resolve —
407
+ * a block a peer just created.
408
+ *
409
+ * Nodes are constructed through `$parseSerializedNode`, the inverse of the
410
+ * `exportJSON` the outbound direction wrote, so custom node types (including
411
+ * `LLuiDecoratorNode`) round-trip through their own `importJSON` with no
412
+ * special-casing here.
413
+ */
414
+ function $buildNode(container, context) {
415
+ const serialized = {
416
+ ...elementProps(container).toJSON(),
417
+ type: elementType(container),
418
+ version: 1,
419
+ };
420
+ const node = $parseSerializedNode(serialized);
421
+ context.mapping.link(containerId(container), node.getKey());
422
+ if ($isElementNode(node)) {
423
+ for (const child of liveChildren(container))
424
+ $appendChild(node, child, context);
425
+ }
426
+ return node;
427
+ }
428
+ /**
429
+ * An element's children, in the order the shared document renders them.
430
+ *
431
+ * The ordering is `sort by (pos, uuid)` over the child carriers — see
432
+ * `order.ts`. This is the ONE place the inbound walk touches the ordering model
433
+ * at all: every carrier is dereferenced to the container the registry addresses
434
+ * it by (the `LoroText` for a run, the element map for an element), and from
435
+ * there this module is exactly as it was under the list schema.
436
+ *
437
+ * ── PROJECTION MUST DEPEND ONLY ON REPLICATED STATE ────────────────────────
438
+ *
439
+ * `orderedChildren` consults no `isDeleted()`, and nothing here may add one.
440
+ * Under the previous `LoroMovableList` schema an earlier version of this
441
+ * function filtered "tombstones" out, reasoning that a shared rule keeps both
442
+ * peers showing the same thing. It does not, and cannot: `isDeleted()` is
443
+ * PEER-LOCAL bookkeeping, not replicated state. The peer that issued a delete
444
+ * kept reporting `true` while every other peer reported `false`, for the same
445
+ * ContainerID in the same list, so it rendered one block fewer than everybody
446
+ * else — permanently, since no later batch ever mentioned the container again.
447
+ *
448
+ * The carrier schema removes the temptation rather than relying on the rule
449
+ * being remembered: a deleted carrier's key is absent from `keys()` on every
450
+ * peer, symmetrically, so the projection is a pure function of the document by
451
+ * construction.
452
+ */
453
+ function liveChildren(container) {
454
+ return orderedChildren(container).map((entry) => entry.container);
455
+ }
456
+ function $appendChild(parent, child, context) {
457
+ if (isTextContainer(child)) {
458
+ const nodes = buildTextNodes(runsFromText(child));
459
+ if (nodes.length === 0)
460
+ return;
461
+ context.mapping.link(containerId(child), nodes[0].getKey());
462
+ for (const node of nodes)
463
+ parent.append(node);
464
+ return;
465
+ }
466
+ parent.append($buildNode(child, context));
467
+ }
468
+ // ---------------------------------------------------------------------------
469
+ // Text runs
470
+ // ---------------------------------------------------------------------------
471
+ function buildTextNodes(runs) {
472
+ return runs.map((run) => {
473
+ const node = $createTextNode(run.text);
474
+ if (run.format !== 0)
475
+ node.setFormat(run.format);
476
+ return node;
477
+ });
478
+ }
479
+ /**
480
+ * Reconcile one text run in place, reusing the existing `TextNode`s.
481
+ *
482
+ * The FIRST node is the run's registry anchor, so keeping it is what keeps the
483
+ * container's address stable across the edit. Nodes are reused positionally and
484
+ * only written when their text or format actually differs, which is what keeps a
485
+ * caret in an unchanged part of the run untouched.
486
+ *
487
+ * An EMPTY container yields zero nodes rather than one empty `TextNode`: the
488
+ * outbound direction EMPTIES a run's last `LoroText` instead of deleting it (so
489
+ * a peer's concurrent insertion into that exact container survives), and an
490
+ * empty run must project as no text at all.
491
+ */
492
+ function $reconcileTextRun(text, existing, context) {
493
+ const target = runsFromText(text);
494
+ const current = normalizeRuns(existing.map((node) => ({ text: node.getTextContent(), format: node.getFormat() })));
495
+ if (runsEqual(current, target))
496
+ return [...existing];
497
+ $transformPoints(current, target, existing, context);
498
+ const out = [];
499
+ for (let i = 0; i < target.length; i++) {
500
+ const run = target[i];
501
+ const node = existing[i];
502
+ if (node === undefined) {
503
+ out.push(buildTextNodes([run])[0]);
504
+ continue;
505
+ }
506
+ if (node.getTextContent() !== run.text)
507
+ node.setTextContent(run.text);
508
+ if (node.getFormat() !== run.format)
509
+ node.setFormat(run.format);
510
+ out.push(node);
511
+ }
512
+ for (let i = target.length; i < existing.length; i++) {
513
+ const node = existing[i];
514
+ context.mapping.unlinkNode(node.getKey());
515
+ node.remove(true);
516
+ context.removed = true;
517
+ }
518
+ context.changed = true;
519
+ $resolvePoints(target, out, context);
520
+ return out;
521
+ }
522
+ function runsEqual(a, b) {
523
+ return (a.length === b.length &&
524
+ a.every((run, i) => run.text === b[i].text && run.format === b[i].format));
525
+ }
526
+ // ---------------------------------------------------------------------------
527
+ // Selection
528
+ // ---------------------------------------------------------------------------
529
+ /**
530
+ * Record where the caret sits, as a run-absolute offset.
531
+ *
532
+ * Only TEXT points are captured. An element point addresses a `NodeKey` this
533
+ * module preserves, so it survives on its own; a text point is the one thing a
534
+ * remote edit to the same run can invalidate.
535
+ */
536
+ function capturePoints(context) {
537
+ const selection = $getSelection();
538
+ if (!$isRangeSelection(selection))
539
+ return;
540
+ for (const point of [selection.anchor, selection.focus]) {
541
+ if (point.type !== 'text')
542
+ continue;
543
+ const node = point.getNode();
544
+ if (!$isTextNode(node))
545
+ continue;
546
+ const run = runNodesFor(node);
547
+ let offset = 0;
548
+ for (const sibling of run) {
549
+ if (sibling.is(node))
550
+ break;
551
+ offset += sibling.getTextContentSize();
552
+ }
553
+ context.points.push({
554
+ point,
555
+ runKeys: run.map((n) => n.getKey()),
556
+ offset: offset + point.offset,
557
+ resolved: null,
558
+ });
559
+ }
560
+ }
561
+ /** The maximal run of adjacent text nodes containing `node`. */
562
+ function runNodesFor(node) {
563
+ const run = [node];
564
+ for (let prev = node.getPreviousSibling(); $isTextNode(prev); prev = prev.getPreviousSibling()) {
565
+ run.unshift(prev);
566
+ }
567
+ for (let next = node.getNextSibling(); $isTextNode(next); next = next.getNextSibling()) {
568
+ run.push(next);
569
+ }
570
+ return run;
571
+ }
572
+ /**
573
+ * Move a captured caret through the text change about to be applied.
574
+ *
575
+ * The change is described as ONE region (`diffTextWithCursor`, biased to the
576
+ * caret so a repeated-character edit is attributed where the user actually is):
577
+ * a caret at or before the region is unmoved, one after it shifts by
578
+ * `insert.length - remove`, and one inside a deleted span clamps to the region's
579
+ * start — which is where a user would expect to be left standing.
580
+ */
581
+ function $transformPoints(current, target, existing, context) {
582
+ const affected = context.points.filter((captured) => existing.some((node) => captured.runKeys.includes(node.getKey())));
583
+ if (affected.length === 0)
584
+ return;
585
+ const before = runsText(current);
586
+ const after = runsText(target);
587
+ for (const captured of affected) {
588
+ const diff = diffTextWithCursor(before, after, captured.offset);
589
+ if (captured.offset <= diff.index)
590
+ continue;
591
+ if (captured.offset <= diff.index + diff.remove)
592
+ captured.offset = diff.index;
593
+ else
594
+ captured.offset += diff.insert.length - diff.remove;
595
+ }
596
+ }
597
+ /** Locate each affected caret inside the rebuilt run. */
598
+ function $resolvePoints(target, nodes, context) {
599
+ for (const captured of context.points) {
600
+ if (!nodes.some((node) => captured.runKeys.includes(node.getKey())))
601
+ continue;
602
+ if (nodes.length === 0)
603
+ continue;
604
+ let remaining = Math.max(0, Math.min(captured.offset, runsText(target).length));
605
+ let resolved = null;
606
+ for (const node of nodes) {
607
+ const size = node.getTextContentSize();
608
+ if (remaining <= size) {
609
+ resolved = { node, offset: remaining };
610
+ break;
611
+ }
612
+ remaining -= size;
613
+ }
614
+ captured.resolved = resolved ?? {
615
+ node: nodes[nodes.length - 1],
616
+ offset: nodes[nodes.length - 1].getTextContentSize(),
617
+ };
618
+ }
619
+ }
620
+ /** Re-place every caret whose run this pass rebuilt. */
621
+ function $restorePoints(context) {
622
+ for (const captured of context.points) {
623
+ const resolved = captured.resolved;
624
+ if (resolved === null)
625
+ continue;
626
+ captured.point.set(resolved.node.getKey(), resolved.offset, 'text');
627
+ }
628
+ // Writing a point mutates the live selection in place; nothing else is needed,
629
+ // but re-setting it makes Lexical mark the selection dirty so the change is
630
+ // reconciled to the DOM.
631
+ const selection = $getSelection();
632
+ if (selection !== null && context.points.some((captured) => captured.resolved !== null)) {
633
+ $setSelection(selection.clone());
634
+ }
635
+ }
636
+ //# sourceMappingURL=to-lexical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"to-lexical.js","sourceRoot":"","sources":["../src/to-lexical.ts"],"names":[],"mappings":"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"}