@getguru/slate-yjs-core 1.0.3

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 (126) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +3 -0
  3. package/dist/applyToSlate/index.d.ts +23 -0
  4. package/dist/applyToSlate/textEvent.d.ts +4 -0
  5. package/dist/applyToYjs/index.d.ts +4 -0
  6. package/dist/applyToYjs/node/index.d.ts +4 -0
  7. package/dist/applyToYjs/node/insertNode.d.ts +4 -0
  8. package/dist/applyToYjs/node/mergeNode.d.ts +4 -0
  9. package/dist/applyToYjs/node/moveNode.d.ts +4 -0
  10. package/dist/applyToYjs/node/removeNode.d.ts +4 -0
  11. package/dist/applyToYjs/node/setNode.d.ts +4 -0
  12. package/dist/applyToYjs/node/splitNode.d.ts +4 -0
  13. package/dist/applyToYjs/text/index.d.ts +4 -0
  14. package/dist/applyToYjs/text/insertText.d.ts +4 -0
  15. package/dist/applyToYjs/text/removeText.d.ts +4 -0
  16. package/dist/applyToYjs/types.d.ts +9 -0
  17. package/dist/index.cjs +1360 -0
  18. package/dist/index.cjs.map +1 -0
  19. package/dist/index.d.ts +6 -0
  20. package/dist/index.global.js +10365 -0
  21. package/dist/index.global.js.map +1 -0
  22. package/dist/index.js +1338 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/model/types.d.ts +38 -0
  25. package/dist/plugins/index.d.ts +4 -0
  26. package/dist/plugins/withCursors.d.ts +39 -0
  27. package/dist/plugins/withYHistory.d.ts +20 -0
  28. package/dist/plugins/withYjs.d.ts +43 -0
  29. package/dist/utils/clone.d.ts +5 -0
  30. package/dist/utils/convert.d.ts +8 -0
  31. package/dist/utils/delta.d.ts +8 -0
  32. package/dist/utils/errors.d.ts +2 -0
  33. package/dist/utils/location.d.ts +12 -0
  34. package/dist/utils/object.d.ts +10 -0
  35. package/dist/utils/position.d.ts +20 -0
  36. package/dist/utils/slate.d.ts +3 -0
  37. package/dist/utils/yjs.d.ts +5 -0
  38. package/package.json +47 -0
  39. package/src/applyToSlate/index.ts +118 -0
  40. package/src/applyToSlate/textEvent.ts +280 -0
  41. package/src/applyToYjs/index.ts +28 -0
  42. package/src/applyToYjs/node/index.ts +17 -0
  43. package/src/applyToYjs/node/insertNode.ts +23 -0
  44. package/src/applyToYjs/node/mergeNode.ts +82 -0
  45. package/src/applyToYjs/node/moveNode.ts +57 -0
  46. package/src/applyToYjs/node/removeNode.ts +16 -0
  47. package/src/applyToYjs/node/setNode.ts +42 -0
  48. package/src/applyToYjs/node/splitNode.ts +98 -0
  49. package/src/applyToYjs/text/index.ts +9 -0
  50. package/src/applyToYjs/text/insertText.ts +27 -0
  51. package/src/applyToYjs/text/removeText.ts +16 -0
  52. package/src/applyToYjs/types.ts +12 -0
  53. package/src/index.ts +47 -0
  54. package/src/model/types.ts +50 -0
  55. package/src/plugins/index.ts +3 -0
  56. package/src/plugins/withCursors.ts +269 -0
  57. package/src/plugins/withYHistory.ts +183 -0
  58. package/src/plugins/withYjs.ts +284 -0
  59. package/src/utils/clone.ts +29 -0
  60. package/src/utils/convert.ts +48 -0
  61. package/src/utils/delta.ts +97 -0
  62. package/src/utils/errors.ts +20 -0
  63. package/src/utils/location.ts +157 -0
  64. package/src/utils/object.ts +93 -0
  65. package/src/utils/position.ts +300 -0
  66. package/src/utils/slate.ts +11 -0
  67. package/src/utils/yjs.ts +10 -0
  68. package/test/collaboration/addMark/acrossMarks.tsx +40 -0
  69. package/test/collaboration/addMark/acrossMarksSame.tsx +36 -0
  70. package/test/collaboration/addMark/atBeginningOfDocument.tsx +27 -0
  71. package/test/collaboration/addMark/atEndOfDocument.tsx +30 -0
  72. package/test/collaboration/addMark/withOtherMarks.tsx +31 -0
  73. package/test/collaboration/insertNode/atBeginningOfDocument.tsx +28 -0
  74. package/test/collaboration/insertNode/atEndOfDocument.tsx +28 -0
  75. package/test/collaboration/insertNode/inTheMiddle.tsx +30 -0
  76. package/test/collaboration/insertText/atBeginningOfBlock.tsx +26 -0
  77. package/test/collaboration/insertText/atBeginningOfDocument.tsx +26 -0
  78. package/test/collaboration/insertText/atEndOfBlock.tsx +26 -0
  79. package/test/collaboration/insertText/atEndOfDocument.tsx +26 -0
  80. package/test/collaboration/insertText/inTheMiddle.tsx +32 -0
  81. package/test/collaboration/insertText/inTheMiddleOfNestedBlock.tsx +30 -0
  82. package/test/collaboration/insertText/insideMarks.tsx +28 -0
  83. package/test/collaboration/insertText/withEmptyString.tsx +25 -0
  84. package/test/collaboration/insertText/withEntities.tsx +28 -0
  85. package/test/collaboration/insertText/withMarks.tsx +25 -0
  86. package/test/collaboration/insertText/withUnicode.tsx +28 -0
  87. package/test/collaboration/mergeNode/afterADeleteBackward.tsx +27 -0
  88. package/test/collaboration/mergeNode/inSameParent.tsx +34 -0
  89. package/test/collaboration/mergeNode/onMixedNestedNodes.tsx +29 -0
  90. package/test/collaboration/mergeNode/onMixedTypeNodes.tsx +27 -0
  91. package/test/collaboration/mergeNode/withUnicode.tsx +25 -0
  92. package/test/collaboration/moveNode/downward/whenBlockBecomesNested.tsx +43 -0
  93. package/test/collaboration/moveNode/downward/whenBlockBecomesNonNested.tsx +41 -0
  94. package/test/collaboration/moveNode/downward/whenBlockStaysNested.tsx +38 -0
  95. package/test/collaboration/moveNode/downward/whenBlockStaysNonNested.tsx +30 -0
  96. package/test/collaboration/moveNode/upward/whenBlockBecomesNested.tsx +43 -0
  97. package/test/collaboration/moveNode/upward/whenBlockBecomesNonNested.tsx +41 -0
  98. package/test/collaboration/moveNode/upward/whenBlockStaysNested.tsx +38 -0
  99. package/test/collaboration/moveNode/upward/whenBlockStaysNonNested.tsx +30 -0
  100. package/test/collaboration/removeMark/inTheMiddleOfText.tsx +43 -0
  101. package/test/collaboration/removeMark/withAddMark.tsx +31 -0
  102. package/test/collaboration/removeMark/withOtherMarks.tsx +47 -0
  103. package/test/collaboration/removeNode/atBeginningOfDocument.tsx +26 -0
  104. package/test/collaboration/removeNode/atEndOfDocument.tsx +26 -0
  105. package/test/collaboration/removeNode/nestedBlock.tsx +28 -0
  106. package/test/collaboration/removeNode/wrapperBlock.tsx +28 -0
  107. package/test/collaboration/removeText/atBeginningOfDocument.tsx +34 -0
  108. package/test/collaboration/removeText/atEndOfDocument.tsx +37 -0
  109. package/test/collaboration/removeText/withUnicode.tsx +29 -0
  110. package/test/collaboration/setNode/atBeginningOfDocument.tsx +27 -0
  111. package/test/collaboration/setNode/atEndOfDocument.tsx +27 -0
  112. package/test/collaboration/setNode/onDataChange.tsx +35 -0
  113. package/test/collaboration/setNode/onDataChangeOnInline.tsx +35 -0
  114. package/test/collaboration/setNode/onResetBlock.tsx +27 -0
  115. package/test/collaboration/setNode/withAChangeOfType.tsx +26 -0
  116. package/test/collaboration/splitNode/atBeginningOfDocument.tsx +28 -0
  117. package/test/collaboration/splitNode/atEndOfBlock.tsx +27 -0
  118. package/test/collaboration/splitNode/atEndOfDocument.tsx +27 -0
  119. package/test/collaboration/splitNode/onNonDefaultBlock.tsx +27 -0
  120. package/test/collaboration/splitNode/withMultipleSubNodes.tsx +32 -0
  121. package/test/collaboration/splitNode/withUnicode.tsx +29 -0
  122. package/test/index.test.ts +65 -0
  123. package/test/slate.d.ts +8 -0
  124. package/test/withTestingElements.ts +46 -0
  125. package/tsconfig.json +11 -0
  126. package/tsup.config.ts +32 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,1360 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __spreadValues = (a, b) => {
13
+ for (var prop in b || (b = {}))
14
+ if (__hasOwnProp.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ if (__getOwnPropSymbols)
17
+ for (var prop of __getOwnPropSymbols(b)) {
18
+ if (__propIsEnum.call(b, prop))
19
+ __defNormalProp(a, prop, b[prop]);
20
+ }
21
+ return a;
22
+ };
23
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
+ var __objRest = (source, exclude) => {
25
+ var target = {};
26
+ for (var prop in source)
27
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
28
+ target[prop] = source[prop];
29
+ if (source != null && __getOwnPropSymbols)
30
+ for (var prop of __getOwnPropSymbols(source)) {
31
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
32
+ target[prop] = source[prop];
33
+ }
34
+ return target;
35
+ };
36
+ var __export = (target, all) => {
37
+ for (var name in all)
38
+ __defProp(target, name, { get: all[name], enumerable: true });
39
+ };
40
+ var __copyProps = (to, from, except, desc) => {
41
+ if (from && typeof from === "object" || typeof from === "function") {
42
+ for (let key of __getOwnPropNames(from))
43
+ if (!__hasOwnProp.call(to, key) && key !== except)
44
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
45
+ }
46
+ return to;
47
+ };
48
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
49
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
50
+
51
+ // src/index.ts
52
+ var src_exports = {};
53
+ __export(src_exports, {
54
+ CursorEditor: () => CursorEditor,
55
+ YHistoryEditor: () => YHistoryEditor,
56
+ YjsEditor: () => YjsEditor,
57
+ relativePositionToSlatePoint: () => relativePositionToSlatePoint,
58
+ relativeRangeToSlateRange: () => relativeRangeToSlateRange,
59
+ slateNodesToInsertDelta: () => slateNodesToInsertDelta,
60
+ slatePointToRelativePosition: () => slatePointToRelativePosition,
61
+ slateRangeToRelativeRange: () => slateRangeToRelativeRange,
62
+ withCursors: () => withCursors,
63
+ withYHistory: () => withYHistory,
64
+ withYjs: () => withYjs,
65
+ yTextToSlateElement: () => yTextToSlateElement
66
+ });
67
+ module.exports = __toCommonJS(src_exports);
68
+
69
+ // src/plugins/withYjs.ts
70
+ var import_slate17 = require("slate");
71
+ var Y8 = __toESM(require("yjs"), 1);
72
+
73
+ // src/applyToSlate/index.ts
74
+ var import_slate8 = require("slate");
75
+ var Y5 = __toESM(require("yjs"), 1);
76
+
77
+ // src/utils/convert.ts
78
+ var import_slate2 = require("slate");
79
+ var Y = __toESM(require("yjs"), 1);
80
+
81
+ // src/utils/object.ts
82
+ function isObject(o) {
83
+ return Object.prototype.toString.call(o) === "[object Object]";
84
+ }
85
+ function isPlainObject(o) {
86
+ if (!isObject(o)) {
87
+ return false;
88
+ }
89
+ const ctor = o.constructor;
90
+ if (ctor === void 0) {
91
+ return true;
92
+ }
93
+ const prot = ctor.prototype;
94
+ if (isObject(prot) === false) {
95
+ return false;
96
+ }
97
+ if (prot.hasOwnProperty("isPrototypeOf") === false) {
98
+ return false;
99
+ }
100
+ return true;
101
+ }
102
+ function deepEquals(node, another) {
103
+ for (const key in node) {
104
+ const a = node[key];
105
+ const b = another[key];
106
+ if (isPlainObject(a) && isPlainObject(b)) {
107
+ if (!deepEquals(a, b)) {
108
+ return false;
109
+ }
110
+ } else if (Array.isArray(a) && Array.isArray(b)) {
111
+ if (a.length !== b.length)
112
+ return false;
113
+ for (let i = 0; i < a.length; i++) {
114
+ if (a[i] !== b[i]) {
115
+ return false;
116
+ }
117
+ }
118
+ } else if (a !== b) {
119
+ return false;
120
+ }
121
+ }
122
+ for (const key in another) {
123
+ if (node[key] === void 0 && another[key] !== void 0) {
124
+ return false;
125
+ }
126
+ }
127
+ return true;
128
+ }
129
+ function pick(obj, ...keys) {
130
+ return Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key)));
131
+ }
132
+ function omit(obj, ...keys) {
133
+ return Object.fromEntries(Object.entries(obj).filter(([key]) => !keys.includes(key)));
134
+ }
135
+ function omitNullEntries(obj) {
136
+ return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== null));
137
+ }
138
+
139
+ // src/utils/delta.ts
140
+ function normalizeInsertDelta(delta) {
141
+ var _a, _b;
142
+ const normalized = [];
143
+ for (const element of delta) {
144
+ if (typeof element.insert === "string" && element.insert.length === 0) {
145
+ continue;
146
+ }
147
+ const prev = normalized[normalized.length - 1];
148
+ if (!prev || typeof prev.insert !== "string" || typeof element.insert !== "string") {
149
+ normalized.push(element);
150
+ continue;
151
+ }
152
+ const merge = prev.attributes === element.attributes || !prev.attributes === !element.attributes && deepEquals((_a = prev.attributes) != null ? _a : {}, (_b = element.attributes) != null ? _b : {});
153
+ if (merge) {
154
+ prev.insert += element.insert;
155
+ continue;
156
+ }
157
+ normalized.push(element);
158
+ }
159
+ return normalized;
160
+ }
161
+ function yTextToInsertDelta(yText) {
162
+ return normalizeInsertDelta(yText.toDelta());
163
+ }
164
+ function getInsertLength({ insert }) {
165
+ return typeof insert === "string" ? insert.length : 1;
166
+ }
167
+ function getInsertDeltaLength(delta) {
168
+ return delta.reduce((curr, element) => curr + getInsertLength(element), 0);
169
+ }
170
+ function sliceInsertDelta(delta, start, length) {
171
+ if (length < 1) {
172
+ return [];
173
+ }
174
+ let currentOffset = 0;
175
+ const sliced = [];
176
+ const end = start + length;
177
+ for (let i = 0; i < delta.length; i++) {
178
+ if (currentOffset >= end) {
179
+ break;
180
+ }
181
+ const element = delta[i];
182
+ const elementLength = getInsertLength(element);
183
+ if (currentOffset + elementLength <= start) {
184
+ currentOffset += elementLength;
185
+ continue;
186
+ }
187
+ if (typeof element.insert !== "string") {
188
+ currentOffset += elementLength;
189
+ sliced.push(element);
190
+ continue;
191
+ }
192
+ const startOffset = Math.max(0, start - currentOffset);
193
+ const endOffset = Math.min(elementLength, elementLength - (currentOffset + elementLength - end));
194
+ sliced.push(__spreadProps(__spreadValues({}, element), {
195
+ insert: element.insert.slice(startOffset, endOffset)
196
+ }));
197
+ currentOffset += elementLength;
198
+ }
199
+ return sliced;
200
+ }
201
+
202
+ // src/utils/slate.ts
203
+ var import_slate = require("slate");
204
+ function getProperties(node) {
205
+ return omit(node, import_slate.Text.isText(node) ? "text" : "children");
206
+ }
207
+
208
+ // src/utils/convert.ts
209
+ function yTextToSlateElement(yText) {
210
+ const delta = yTextToInsertDelta(yText);
211
+ const children = delta.length > 0 ? delta.map(deltaInsertToSlateNode) : [{ text: "" }];
212
+ return __spreadProps(__spreadValues({}, yText.getAttributes()), { children });
213
+ }
214
+ function deltaInsertToSlateNode(insert) {
215
+ if (typeof insert.insert === "string") {
216
+ return __spreadProps(__spreadValues({}, insert.attributes), { text: insert.insert });
217
+ }
218
+ return yTextToSlateElement(insert.insert);
219
+ }
220
+ function slateNodesToInsertDelta(nodes) {
221
+ return nodes.map((node) => {
222
+ if (import_slate2.Text.isText(node)) {
223
+ return { insert: node.text, attributes: getProperties(node) };
224
+ }
225
+ return { insert: slateElementToYText(node) };
226
+ });
227
+ }
228
+ function slateElementToYText(_a) {
229
+ var _b = _a, {
230
+ children
231
+ } = _b, attributes = __objRest(_b, [
232
+ "children"
233
+ ]);
234
+ const yElement = new Y.XmlText();
235
+ Object.entries(attributes).forEach(([key, value]) => {
236
+ yElement.setAttribute(key, value);
237
+ });
238
+ yElement.applyDelta(slateNodesToInsertDelta(children), { sanitize: false });
239
+ return yElement;
240
+ }
241
+
242
+ // src/utils/errors.ts
243
+ var SYNC_SKEW_ERROR_PATTERNS = [
244
+ "Cannot find a descendant at path",
245
+ "yOffset out of bounds",
246
+ "Cannot descent into slate text",
247
+ "yText isn't a descendant of root element",
248
+ "Path doesn't match yText",
249
+ "Unexpected y parent type",
250
+ "Path has to a have a length >= 1",
251
+ "yTarget spans multiple nodes"
252
+ ];
253
+ function isSyncSkewError(error) {
254
+ if (!(error instanceof Error)) {
255
+ return false;
256
+ }
257
+ return SYNC_SKEW_ERROR_PATTERNS.some((pattern) => error.message.includes(pattern));
258
+ }
259
+
260
+ // src/utils/position.ts
261
+ var import_slate5 = require("slate");
262
+ var Y3 = __toESM(require("yjs"), 1);
263
+
264
+ // src/utils/location.ts
265
+ var import_slate4 = require("slate");
266
+ var Y2 = __toESM(require("yjs"), 1);
267
+ function getSlateNodeYLength(node) {
268
+ if (!node) {
269
+ return 0;
270
+ }
271
+ return import_slate4.Text.isText(node) ? node.text.length : 1;
272
+ }
273
+ function slatePathOffsetToYOffset(element, pathOffset) {
274
+ return element.children.slice(0, pathOffset).reduce((yOffset, node) => yOffset + getSlateNodeYLength(node), 0);
275
+ }
276
+ function getYTarget(yRoot, slateRoot, path) {
277
+ var _a;
278
+ if (path.length === 0) {
279
+ throw new Error("Path has to a have a length >= 1");
280
+ }
281
+ if (import_slate4.Text.isText(slateRoot)) {
282
+ throw new Error("Cannot descent into slate text");
283
+ }
284
+ const [pathOffset, ...childPath] = path;
285
+ const yOffset = slatePathOffsetToYOffset(slateRoot, pathOffset);
286
+ const targetNode = slateRoot.children[pathOffset];
287
+ const delta = yTextToInsertDelta(yRoot);
288
+ const targetLength = getSlateNodeYLength(targetNode);
289
+ const targetDelta = sliceInsertDelta(delta, yOffset, targetLength);
290
+ if (targetDelta.length > 1) {
291
+ throw new Error("Path doesn't match yText, yTarget spans multiple nodes");
292
+ }
293
+ const yTarget = (_a = targetDelta[0]) == null ? void 0 : _a.insert;
294
+ if (childPath.length > 0) {
295
+ if (!(yTarget instanceof Y2.XmlText)) {
296
+ throw new Error("Path doesn't match yText, cannot descent into non-yText");
297
+ }
298
+ return getYTarget(yTarget, targetNode, childPath);
299
+ }
300
+ return {
301
+ yParent: yRoot,
302
+ textRange: { start: yOffset, end: yOffset + targetLength },
303
+ yTarget: yTarget instanceof Y2.XmlText ? yTarget : void 0,
304
+ slateParent: slateRoot,
305
+ slateTarget: targetNode,
306
+ targetDelta
307
+ };
308
+ }
309
+ function yOffsetToSlateOffsets(parent, yOffset, opts = {}) {
310
+ const { assoc = 0, insert = false } = opts;
311
+ let currentOffset = 0;
312
+ let lastNonEmptyPathOffset = 0;
313
+ for (let pathOffset = 0; pathOffset < parent.children.length; pathOffset++) {
314
+ const child2 = parent.children[pathOffset];
315
+ const nodeLength = import_slate4.Text.isText(child2) ? child2.text.length : 1;
316
+ if (nodeLength > 0) {
317
+ lastNonEmptyPathOffset = pathOffset;
318
+ }
319
+ const endOffset = currentOffset + nodeLength;
320
+ if (nodeLength > 0 && (assoc >= 0 ? endOffset > yOffset : endOffset >= yOffset)) {
321
+ return [pathOffset, yOffset - currentOffset];
322
+ }
323
+ currentOffset += nodeLength;
324
+ }
325
+ if (yOffset > currentOffset + (insert ? 1 : 0)) {
326
+ throw new Error("yOffset out of bounds");
327
+ }
328
+ if (insert) {
329
+ return [parent.children.length, 0];
330
+ }
331
+ const child = parent.children[lastNonEmptyPathOffset];
332
+ const textOffset = import_slate4.Text.isText(child) ? child.text.length : 1;
333
+ return [lastNonEmptyPathOffset, textOffset];
334
+ }
335
+ function getSlatePath(sharedRoot, slateRoot, yText) {
336
+ const yNodePath = [yText];
337
+ while (yNodePath[0] !== sharedRoot) {
338
+ const { parent: yParent } = yNodePath[0];
339
+ if (!yParent) {
340
+ throw new Error("yText isn't a descendant of root element");
341
+ }
342
+ if (!(yParent instanceof Y2.XmlText)) {
343
+ throw new Error("Unexpected y parent type");
344
+ }
345
+ yNodePath.unshift(yParent);
346
+ }
347
+ if (yNodePath.length < 2) {
348
+ return [];
349
+ }
350
+ let slateParent = slateRoot;
351
+ return yNodePath.reduce((path, yParent, idx) => {
352
+ const yChild = yNodePath[idx + 1];
353
+ if (!yChild) {
354
+ return path;
355
+ }
356
+ let yOffset = 0;
357
+ const currentDelta = yTextToInsertDelta(yParent);
358
+ for (const element of currentDelta) {
359
+ if (element.insert === yChild) {
360
+ break;
361
+ }
362
+ yOffset += typeof element.insert === "string" ? element.insert.length : 1;
363
+ }
364
+ if (import_slate4.Text.isText(slateParent)) {
365
+ throw new Error("Cannot descent into slate text");
366
+ }
367
+ const [pathOffset] = yOffsetToSlateOffsets(slateParent, yOffset);
368
+ slateParent = slateParent.children[pathOffset];
369
+ return path.concat(pathOffset);
370
+ }, []);
371
+ }
372
+
373
+ // src/utils/yjs.ts
374
+ function assertDocumentAttachment(sharedType) {
375
+ if (!sharedType.doc) {
376
+ throw new Error("shared type isn't attached to a document");
377
+ }
378
+ }
379
+
380
+ // src/utils/position.ts
381
+ var STORED_POSITION_PREFIX = "__slateYjsStoredPosition_";
382
+ function slatePointToRelativePosition(sharedRoot, slateRoot, point) {
383
+ const { yTarget, yParent, textRange } = getYTarget(sharedRoot, slateRoot, point.path);
384
+ if (yTarget) {
385
+ throw new Error("Slate point points to a non-text element inside sharedRoot");
386
+ }
387
+ const index = textRange.start + point.offset;
388
+ return Y3.createRelativePositionFromTypeIndex(yParent, index, index === textRange.end ? -1 : 0);
389
+ }
390
+ function absolutePositionToSlatePoint(sharedRoot, slateRoot, { type, index, assoc }) {
391
+ if (!(type instanceof Y3.XmlText)) {
392
+ throw new Error("Absolute position points to a non-XMLText");
393
+ }
394
+ try {
395
+ const parentPath = getSlatePath(sharedRoot, slateRoot, type);
396
+ const parent = import_slate5.Node.get(slateRoot, parentPath);
397
+ if (import_slate5.Text.isText(parent)) {
398
+ return null;
399
+ }
400
+ const [pathOffset, textOffset] = yOffsetToSlateOffsets(parent, index, {
401
+ assoc
402
+ });
403
+ const target = parent.children[pathOffset];
404
+ if (!import_slate5.Text.isText(target)) {
405
+ return null;
406
+ }
407
+ return { path: [...parentPath, pathOffset], offset: textOffset };
408
+ } catch (error) {
409
+ if (isSyncSkewError(error)) {
410
+ return null;
411
+ }
412
+ throw error;
413
+ }
414
+ }
415
+ function relativePositionToSlatePoint(sharedRoot, slateRoot, pos) {
416
+ if (!sharedRoot.doc) {
417
+ throw new Error("sharedRoot isn't attach to a yDoc");
418
+ }
419
+ const absPos = Y3.createAbsolutePositionFromRelativePosition(pos, sharedRoot.doc);
420
+ return absPos && absolutePositionToSlatePoint(sharedRoot, slateRoot, absPos);
421
+ }
422
+ function getStoredPosition(sharedRoot, key) {
423
+ const rawPosition = sharedRoot.getAttribute(STORED_POSITION_PREFIX + key);
424
+ if (!rawPosition) {
425
+ return null;
426
+ }
427
+ return Y3.decodeRelativePosition(rawPosition);
428
+ }
429
+ function getStoredPositions(sharedRoot) {
430
+ return Object.fromEntries(Object.entries(sharedRoot.getAttributes()).filter(([key]) => key.startsWith(STORED_POSITION_PREFIX)).map(([key, position]) => [
431
+ key.slice(STORED_POSITION_PREFIX.length),
432
+ Y3.createRelativePositionFromJSON(position)
433
+ ]));
434
+ }
435
+ function getStoredPositionsAbsolute(sharedRoot) {
436
+ assertDocumentAttachment(sharedRoot);
437
+ return Object.fromEntries(Object.entries(sharedRoot.getAttributes()).filter(([key]) => key.startsWith(STORED_POSITION_PREFIX)).map(([key, position]) => [
438
+ key.slice(STORED_POSITION_PREFIX.length),
439
+ Y3.createAbsolutePositionFromRelativePosition(Y3.decodeRelativePosition(position), sharedRoot.doc)
440
+ ]).filter(([, position]) => position));
441
+ }
442
+ function removeStoredPosition(sharedRoot, key) {
443
+ sharedRoot.removeAttribute(STORED_POSITION_PREFIX + key);
444
+ }
445
+ function setStoredPosition(sharedRoot, key, position) {
446
+ sharedRoot.setAttribute(STORED_POSITION_PREFIX + key, Y3.encodeRelativePosition(position));
447
+ }
448
+ function getAbsolutePositionsInTextRange(absolutePositions, yTarget, textRange) {
449
+ return Object.fromEntries(Object.entries(absolutePositions).filter(([, position]) => {
450
+ if (position.type !== yTarget) {
451
+ return false;
452
+ }
453
+ if (!textRange) {
454
+ return true;
455
+ }
456
+ return position.assoc >= 0 ? position.index >= textRange.start && position.index < textRange.end : position.index > textRange.start && position.index >= textRange.end;
457
+ }));
458
+ }
459
+ function getAbsolutePositionsInYText(absolutePositions, yText, parentPath = "") {
460
+ const positions = {
461
+ [parentPath]: getAbsolutePositionsInTextRange(absolutePositions, yText)
462
+ };
463
+ const insertDelta = yTextToInsertDelta(yText);
464
+ insertDelta.forEach(({ insert }, i) => {
465
+ if (insert instanceof Y3.XmlText) {
466
+ Object.assign(positions, getAbsolutePositionsInYText(absolutePositions, insert, parentPath ? `${parentPath}.${i}` : i.toString()));
467
+ }
468
+ });
469
+ return positions;
470
+ }
471
+ function getStoredPositionsInDeltaAbsolute(sharedRoot, yText, delta, deltaOffset = 0) {
472
+ const absolutePositions = getStoredPositionsAbsolute(sharedRoot);
473
+ const positions = {
474
+ "": getAbsolutePositionsInTextRange(absolutePositions, yText, {
475
+ start: deltaOffset,
476
+ end: deltaOffset + getInsertDeltaLength(delta)
477
+ })
478
+ };
479
+ delta.forEach(({ insert }, i) => {
480
+ if (insert instanceof Y3.XmlText) {
481
+ Object.assign(positions, getAbsolutePositionsInYText(absolutePositions, insert, i.toString()));
482
+ }
483
+ });
484
+ return positions;
485
+ }
486
+ function restoreStoredPositionsWithDeltaAbsolute(sharedRoot, yText, absolutePositions, delta, newDeltaOffset = 0, previousDeltaOffset = 0, path = "") {
487
+ const toRestore = absolutePositions[path];
488
+ if (toRestore) {
489
+ Object.entries(toRestore).forEach(([key, position]) => {
490
+ setStoredPosition(sharedRoot, key, Y3.createRelativePositionFromTypeIndex(yText, position.index - previousDeltaOffset + newDeltaOffset, position.assoc));
491
+ });
492
+ }
493
+ delta.forEach(({ insert }, i) => {
494
+ if (insert instanceof Y3.XmlText) {
495
+ restoreStoredPositionsWithDeltaAbsolute(sharedRoot, insert, absolutePositions, yTextToInsertDelta(insert), 0, 0, path ? `${path}.${i}` : i.toString());
496
+ }
497
+ });
498
+ }
499
+ function slateRangeToRelativeRange(sharedRoot, slateRoot, range) {
500
+ return {
501
+ anchor: slatePointToRelativePosition(sharedRoot, slateRoot, range.anchor),
502
+ focus: slatePointToRelativePosition(sharedRoot, slateRoot, range.focus)
503
+ };
504
+ }
505
+ function relativeRangeToSlateRange(sharedRoot, slateRoot, range) {
506
+ const anchor = relativePositionToSlatePoint(sharedRoot, slateRoot, range.anchor);
507
+ if (!anchor) {
508
+ return null;
509
+ }
510
+ const focus = relativePositionToSlatePoint(sharedRoot, slateRoot, range.focus);
511
+ if (!focus) {
512
+ return null;
513
+ }
514
+ return { anchor, focus };
515
+ }
516
+
517
+ // src/applyToSlate/textEvent.ts
518
+ var import_slate6 = require("slate");
519
+ var Y4 = __toESM(require("yjs"), 1);
520
+ function applyDelta(node, slatePath, delta) {
521
+ const ops = [];
522
+ let yOffset = delta.reduce((length, change) => {
523
+ if ("retain" in change) {
524
+ return length + change.retain;
525
+ }
526
+ if ("delete" in change) {
527
+ return length + change.delete;
528
+ }
529
+ return length;
530
+ }, 0);
531
+ delta.reverse().forEach((change) => {
532
+ var _a;
533
+ if ("attributes" in change && "retain" in change) {
534
+ const [startPathOffset, startTextOffset] = yOffsetToSlateOffsets(node, yOffset - change.retain);
535
+ const [endPathOffset, endTextOffset] = yOffsetToSlateOffsets(node, yOffset, { assoc: -1 });
536
+ for (let pathOffset = endPathOffset; pathOffset >= startPathOffset; pathOffset--) {
537
+ const child = node.children[pathOffset];
538
+ const childPath = [...slatePath, pathOffset];
539
+ if (!import_slate6.Text.isText(child)) {
540
+ continue;
541
+ }
542
+ const newProperties = change.attributes;
543
+ const properties = pick(node, ...Object.keys(change.attributes));
544
+ if (pathOffset === startPathOffset || pathOffset === endPathOffset) {
545
+ const start = pathOffset === startPathOffset ? startTextOffset : 0;
546
+ const end = pathOffset === endPathOffset ? endTextOffset : child.text.length;
547
+ if (end !== child.text.length) {
548
+ ops.push({
549
+ type: "split_node",
550
+ path: childPath,
551
+ position: end,
552
+ properties: getProperties(child)
553
+ });
554
+ }
555
+ if (start !== 0) {
556
+ ops.push({
557
+ type: "split_node",
558
+ path: childPath,
559
+ position: start,
560
+ properties: omitNullEntries(__spreadValues(__spreadValues({}, getProperties(child)), newProperties))
561
+ });
562
+ continue;
563
+ }
564
+ }
565
+ ops.push({
566
+ type: "set_node",
567
+ newProperties,
568
+ path: childPath,
569
+ properties
570
+ });
571
+ }
572
+ }
573
+ if ("retain" in change) {
574
+ yOffset -= change.retain;
575
+ }
576
+ if ("delete" in change) {
577
+ const [startPathOffset, startTextOffset] = yOffsetToSlateOffsets(node, yOffset - change.delete);
578
+ const [endPathOffset, endTextOffset] = yOffsetToSlateOffsets(node, yOffset, { assoc: -1 });
579
+ for (let pathOffset = endTextOffset === 0 ? endPathOffset - 1 : endPathOffset; pathOffset >= startPathOffset; pathOffset--) {
580
+ const child = node.children[pathOffset];
581
+ const childPath = [...slatePath, pathOffset];
582
+ if (import_slate6.Text.isText(child) && (pathOffset === startPathOffset || pathOffset === endPathOffset)) {
583
+ const start = pathOffset === startPathOffset ? startTextOffset : 0;
584
+ const end = pathOffset === endPathOffset ? endTextOffset : child.text.length;
585
+ ops.push({
586
+ type: "remove_text",
587
+ offset: start,
588
+ text: child.text.slice(start, end),
589
+ path: childPath
590
+ });
591
+ yOffset -= end - start;
592
+ continue;
593
+ }
594
+ ops.push({
595
+ type: "remove_node",
596
+ node: child,
597
+ path: childPath
598
+ });
599
+ yOffset -= getSlateNodeYLength(child);
600
+ }
601
+ return;
602
+ }
603
+ if ("insert" in change) {
604
+ const [pathOffset, textOffset] = yOffsetToSlateOffsets(node, yOffset, {
605
+ insert: true
606
+ });
607
+ const child = node.children[pathOffset];
608
+ const childPath = [...slatePath, pathOffset];
609
+ if (import_slate6.Text.isText(child)) {
610
+ const lastOp = ops[ops.length - 1];
611
+ const currentProps = lastOp != null && lastOp.type === "insert_node" ? lastOp.node : getProperties(child);
612
+ let lastPath = [];
613
+ if (lastOp != null && (lastOp.type === "insert_node" || lastOp.type === "insert_text" || lastOp.type === "split_node" || lastOp.type === "set_node")) {
614
+ lastPath = lastOp.path;
615
+ }
616
+ if (typeof change.insert === "string" && deepEquals((_a = change.attributes) != null ? _a : {}, currentProps) && import_slate6.Path.equals(childPath, lastPath)) {
617
+ return ops.push({
618
+ type: "insert_text",
619
+ offset: textOffset,
620
+ text: change.insert,
621
+ path: childPath
622
+ });
623
+ }
624
+ const toInsert = deltaInsertToSlateNode(change);
625
+ if (textOffset === 0) {
626
+ return ops.push({
627
+ type: "insert_node",
628
+ path: childPath,
629
+ node: toInsert
630
+ });
631
+ }
632
+ if (textOffset < child.text.length) {
633
+ ops.push({
634
+ type: "split_node",
635
+ path: childPath,
636
+ position: textOffset,
637
+ properties: getProperties(child)
638
+ });
639
+ }
640
+ return ops.push({
641
+ type: "insert_node",
642
+ path: import_slate6.Path.next(childPath),
643
+ node: toInsert
644
+ });
645
+ }
646
+ return ops.push({
647
+ type: "insert_node",
648
+ path: childPath,
649
+ node: deltaInsertToSlateNode(change)
650
+ });
651
+ }
652
+ });
653
+ return ops;
654
+ }
655
+ function translateYTextEvent(sharedRoot, editor, event) {
656
+ const { target, changes } = event;
657
+ const delta = event.delta;
658
+ if (!(target instanceof Y4.XmlText)) {
659
+ throw new Error("Unexpected target node type");
660
+ }
661
+ const ops = [];
662
+ const slatePath = getSlatePath(sharedRoot, editor, target);
663
+ const targetElement = import_slate6.Node.get(editor, slatePath);
664
+ if (import_slate6.Text.isText(targetElement)) {
665
+ throw new Error("Cannot apply yTextEvent to text node");
666
+ }
667
+ const keyChanges = Array.from(changes.keys.entries());
668
+ if (slatePath.length > 0 && keyChanges.length > 0) {
669
+ const newProperties = Object.fromEntries(keyChanges.map(([key, info]) => [
670
+ key,
671
+ info.action === "delete" ? null : target.getAttribute(key)
672
+ ]));
673
+ const properties = Object.fromEntries(keyChanges.map(([key]) => [key, targetElement[key]]));
674
+ ops.push({ type: "set_node", newProperties, properties, path: slatePath });
675
+ }
676
+ if (delta.length > 0) {
677
+ ops.push(...applyDelta(targetElement, slatePath, delta));
678
+ }
679
+ return ops;
680
+ }
681
+
682
+ // src/applyToSlate/index.ts
683
+ var lastResyncTime = 0;
684
+ var RESYNC_THROTTLE_MS = 1e3;
685
+ function translateYjsEvent(sharedRoot, editor, event) {
686
+ if (event instanceof Y5.YTextEvent) {
687
+ return translateYTextEvent(sharedRoot, editor, event);
688
+ }
689
+ throw new Error("Unexpected Y event type");
690
+ }
691
+ function resyncFromYjs(sharedRoot, editor) {
692
+ let savedSelection = null;
693
+ try {
694
+ if (editor.selection) {
695
+ savedSelection = slateRangeToRelativeRange(sharedRoot, editor, editor.selection);
696
+ }
697
+ } catch {
698
+ }
699
+ const content = yTextToSlateElement(sharedRoot);
700
+ editor.children = content.children;
701
+ import_slate8.Editor.normalize(editor, { force: true });
702
+ if (savedSelection) {
703
+ try {
704
+ const newSelection = relativeRangeToSlateRange(sharedRoot, editor, savedSelection);
705
+ if (newSelection) {
706
+ import_slate8.Transforms.select(editor, newSelection);
707
+ }
708
+ } catch {
709
+ }
710
+ }
711
+ }
712
+ function applyYjsEvents(sharedRoot, editor, events) {
713
+ import_slate8.Editor.withoutNormalizing(editor, () => {
714
+ for (const event of events) {
715
+ try {
716
+ const ops = translateYjsEvent(sharedRoot, editor, event);
717
+ for (const op of ops) {
718
+ editor.apply(op);
719
+ }
720
+ } catch (error) {
721
+ if (isSyncSkewError(error)) {
722
+ const now = Date.now();
723
+ if (now - lastResyncTime >= RESYNC_THROTTLE_MS) {
724
+ lastResyncTime = now;
725
+ console.warn("[slate-yjs] Sync skew detected, re-syncing from Yjs:", error instanceof Error ? error.message : error);
726
+ resyncFromYjs(sharedRoot, editor);
727
+ } else {
728
+ console.warn("[slate-yjs] Sync skew detected (throttled, skipping re-sync):", error instanceof Error ? error.message : error);
729
+ }
730
+ return;
731
+ }
732
+ throw error;
733
+ }
734
+ }
735
+ });
736
+ }
737
+
738
+ // src/applyToYjs/node/insertNode.ts
739
+ var import_slate9 = require("slate");
740
+ function insertNode(sharedRoot, slateRoot, op) {
741
+ const { yParent, textRange } = getYTarget(sharedRoot, slateRoot, op.path);
742
+ if (import_slate9.Text.isText(op.node)) {
743
+ return yParent.insert(textRange.start, op.node.text, getProperties(op.node));
744
+ }
745
+ yParent.insertEmbed(textRange.start, slateElementToYText(op.node));
746
+ }
747
+
748
+ // src/applyToYjs/node/mergeNode.ts
749
+ var import_slate11 = require("slate");
750
+
751
+ // src/utils/clone.ts
752
+ var Y6 = __toESM(require("yjs"), 1);
753
+ function cloneInsertDeltaDeep(delta) {
754
+ return delta.map((element) => {
755
+ if (typeof element.insert === "string") {
756
+ return element;
757
+ }
758
+ return __spreadProps(__spreadValues({}, element), { insert: cloneDeep(element.insert) });
759
+ });
760
+ }
761
+ function cloneDeep(yText) {
762
+ const clone = new Y6.XmlText();
763
+ const attributes = yText.getAttributes();
764
+ Object.entries(attributes).forEach(([key, value]) => {
765
+ clone.setAttribute(key, value);
766
+ });
767
+ clone.applyDelta(cloneInsertDeltaDeep(yTextToInsertDelta(yText)), {
768
+ sanitize: false
769
+ });
770
+ return clone;
771
+ }
772
+
773
+ // src/applyToYjs/node/mergeNode.ts
774
+ function mergeNode(sharedRoot, slateRoot, op) {
775
+ const target = getYTarget(sharedRoot, slateRoot, op.path);
776
+ const prev = getYTarget(target.yParent, target.slateParent, import_slate11.Path.previous(op.path.slice(-1)));
777
+ if (!target.yTarget !== !prev.yTarget) {
778
+ throw new Error("Cannot merge y text with y element");
779
+ }
780
+ if (!prev.yTarget || !target.yTarget) {
781
+ const { yParent: parent, textRange, slateTarget } = target;
782
+ if (!slateTarget) {
783
+ throw new Error("Expected Slate target node for merge op.");
784
+ }
785
+ const prevSibling = import_slate11.Node.get(slateRoot, import_slate11.Path.previous(op.path));
786
+ if (!import_slate11.Text.isText(prevSibling)) {
787
+ throw new Error("Path points to Y.Text but not a Slate text node.");
788
+ }
789
+ const targetProps = getProperties(slateTarget);
790
+ const prevSiblingProps = getProperties(prevSibling);
791
+ const unsetProps = Object.keys(targetProps).reduce((acc, key) => {
792
+ const prevSiblingHasProp = key in prevSiblingProps;
793
+ return prevSiblingHasProp ? acc : __spreadProps(__spreadValues({}, acc), { [key]: null });
794
+ }, {});
795
+ return parent.format(textRange.start, textRange.end - textRange.start, __spreadValues(__spreadValues({}, unsetProps), prevSiblingProps));
796
+ }
797
+ const deltaApplyYOffset = prev.yTarget.length;
798
+ const targetDelta = yTextToInsertDelta(target.yTarget);
799
+ const clonedDelta = cloneInsertDeltaDeep(targetDelta);
800
+ const storedPositions = getStoredPositionsInDeltaAbsolute(sharedRoot, target.yTarget, targetDelta, deltaApplyYOffset);
801
+ const applyDelta2 = [{ retain: deltaApplyYOffset }, ...clonedDelta];
802
+ prev.yTarget.applyDelta(applyDelta2, {
803
+ sanitize: false
804
+ });
805
+ target.yParent.delete(target.textRange.start, target.textRange.end - target.textRange.start);
806
+ restoreStoredPositionsWithDeltaAbsolute(sharedRoot, prev.yTarget, storedPositions, clonedDelta, deltaApplyYOffset);
807
+ }
808
+
809
+ // src/applyToYjs/node/moveNode.ts
810
+ var import_slate13 = require("slate");
811
+ function moveNode(sharedRoot, slateRoot, op) {
812
+ const newParentPath = import_slate13.Path.parent(op.newPath);
813
+ const newPathOffset = op.newPath[op.newPath.length - 1];
814
+ const parent = import_slate13.Node.get(slateRoot, newParentPath);
815
+ if (import_slate13.Text.isText(parent)) {
816
+ throw new Error("Cannot move slate node into text element");
817
+ }
818
+ const normalizedNewPath = [
819
+ ...newParentPath,
820
+ Math.min(newPathOffset, parent.children.length)
821
+ ];
822
+ const origin = getYTarget(sharedRoot, slateRoot, op.path);
823
+ const target = getYTarget(sharedRoot, slateRoot, normalizedNewPath);
824
+ const insertDelta = cloneInsertDeltaDeep(origin.targetDelta);
825
+ const storedPositions = getStoredPositionsInDeltaAbsolute(sharedRoot, origin.yParent, origin.targetDelta);
826
+ origin.yParent.delete(origin.textRange.start, origin.textRange.end - origin.textRange.start);
827
+ const targetLength = getInsertDeltaLength(yTextToInsertDelta(target.yParent));
828
+ const deltaApplyYOffset = Math.min(target.textRange.start, targetLength);
829
+ const applyDelta2 = [{ retain: deltaApplyYOffset }, ...insertDelta];
830
+ target.yParent.applyDelta(applyDelta2, { sanitize: false });
831
+ restoreStoredPositionsWithDeltaAbsolute(sharedRoot, target.yParent, storedPositions, insertDelta, deltaApplyYOffset, origin.textRange.start);
832
+ }
833
+
834
+ // src/applyToYjs/node/removeNode.ts
835
+ function removeNode(sharedRoot, slateRoot, op) {
836
+ const { yParent: parent, textRange } = getYTarget(sharedRoot, slateRoot, op.path);
837
+ parent.delete(textRange.start, textRange.end - textRange.start);
838
+ }
839
+
840
+ // src/applyToYjs/node/setNode.ts
841
+ function setNode(sharedRoot, slateRoot, op) {
842
+ const { yTarget, textRange, yParent } = getYTarget(sharedRoot, slateRoot, op.path);
843
+ if (yTarget) {
844
+ Object.entries(op.newProperties).forEach(([key, value]) => {
845
+ if (value === null) {
846
+ return yTarget.removeAttribute(key);
847
+ }
848
+ yTarget.setAttribute(key, value);
849
+ });
850
+ return Object.entries(op.properties).forEach(([key]) => {
851
+ if (!op.newProperties.hasOwnProperty(key)) {
852
+ yTarget.removeAttribute(key);
853
+ }
854
+ });
855
+ }
856
+ const unset = Object.fromEntries(Object.keys(op.properties).map((key) => [key, null]));
857
+ const newProperties = __spreadValues(__spreadValues({}, unset), op.newProperties);
858
+ yParent.format(textRange.start, textRange.end - textRange.start, newProperties);
859
+ }
860
+
861
+ // src/applyToYjs/node/splitNode.ts
862
+ var import_slate14 = require("slate");
863
+ var Y7 = __toESM(require("yjs"), 1);
864
+ function splitNode(sharedRoot, slateRoot, op) {
865
+ const target = getYTarget(sharedRoot, slateRoot, op.path);
866
+ if (!target.slateTarget) {
867
+ throw new Error("Y target without corresponding slate node");
868
+ }
869
+ if (!target.yTarget) {
870
+ if (!import_slate14.Text.isText(target.slateTarget)) {
871
+ throw new Error("Mismatch node type between y target and slate node");
872
+ }
873
+ const unset = {};
874
+ target.targetDelta.forEach((element) => {
875
+ if (element.attributes) {
876
+ Object.keys(element.attributes).forEach((key) => {
877
+ unset[key] = null;
878
+ });
879
+ }
880
+ });
881
+ return target.yParent.format(target.textRange.start, target.textRange.end - target.textRange.start, __spreadValues(__spreadValues({}, unset), op.properties));
882
+ }
883
+ if (import_slate14.Text.isText(target.slateTarget)) {
884
+ throw new Error("Mismatch node type between y target and slate node");
885
+ }
886
+ const splitTarget = getYTarget(target.yTarget, target.slateTarget, [
887
+ op.position
888
+ ]);
889
+ const ySplitOffset = target.slateTarget.children.slice(0, op.position).reduce((length2, child) => length2 + getSlateNodeYLength(child), 0);
890
+ const length = target.slateTarget.children.reduce((current, child) => current + getSlateNodeYLength(child), 0);
891
+ const splitDelta = sliceInsertDelta(yTextToInsertDelta(target.yTarget), ySplitOffset, length - ySplitOffset);
892
+ const clonedDelta = cloneInsertDeltaDeep(splitDelta);
893
+ const storedPositions = getStoredPositionsInDeltaAbsolute(sharedRoot, target.yTarget, splitDelta, ySplitOffset);
894
+ const toInsert = new Y7.XmlText();
895
+ toInsert.applyDelta(clonedDelta, {
896
+ sanitize: false
897
+ });
898
+ Object.entries(op.properties).forEach(([key, value]) => {
899
+ toInsert.setAttribute(key, value);
900
+ });
901
+ target.yTarget.delete(splitTarget.textRange.start, target.yTarget.length - splitTarget.textRange.start);
902
+ target.yParent.insertEmbed(target.textRange.end, toInsert);
903
+ restoreStoredPositionsWithDeltaAbsolute(sharedRoot, toInsert, storedPositions, clonedDelta, 0, ySplitOffset);
904
+ }
905
+
906
+ // src/applyToYjs/node/index.ts
907
+ var NODE_MAPPER = {
908
+ insert_node: insertNode,
909
+ remove_node: removeNode,
910
+ set_node: setNode,
911
+ merge_node: mergeNode,
912
+ move_node: moveNode,
913
+ split_node: splitNode
914
+ };
915
+
916
+ // src/applyToYjs/text/insertText.ts
917
+ var import_slate15 = require("slate");
918
+ function insertText(sharedRoot, slateRoot, op) {
919
+ const { yParent: target, textRange } = getYTarget(sharedRoot, slateRoot, op.path);
920
+ const targetNode = import_slate15.Node.get(slateRoot, op.path);
921
+ if (!import_slate15.Text.isText(targetNode)) {
922
+ throw new Error("Cannot insert text into non-text node");
923
+ }
924
+ target.insert(textRange.start + op.offset, op.text, getProperties(targetNode));
925
+ }
926
+
927
+ // src/applyToYjs/text/removeText.ts
928
+ function removeText(sharedRoot, slateRoot, op) {
929
+ const { yParent: target, textRange } = getYTarget(sharedRoot, slateRoot, op.path);
930
+ target.delete(textRange.start + op.offset, op.text.length);
931
+ }
932
+
933
+ // src/applyToYjs/text/index.ts
934
+ var TEXT_MAPPER = {
935
+ insert_text: insertText,
936
+ remove_text: removeText
937
+ };
938
+
939
+ // src/applyToYjs/index.ts
940
+ var NOOP = () => {
941
+ };
942
+ var opMappers = __spreadProps(__spreadValues(__spreadValues({}, TEXT_MAPPER), NODE_MAPPER), {
943
+ set_selection: NOOP
944
+ });
945
+ function applySlateOp(sharedRoot, slateRoot, op) {
946
+ const apply = opMappers[op.type];
947
+ if (!apply) {
948
+ throw new Error(`Unknown operation: ${op.type}`);
949
+ }
950
+ apply(sharedRoot, slateRoot, op);
951
+ }
952
+
953
+ // src/plugins/withYjs.ts
954
+ var DEFAULT_LOCAL_ORIGIN = Symbol("slate-yjs-operation");
955
+ var DEFAULT_POSITION_STORAGE_ORIGIN = Symbol("slate-yjs-position-storage");
956
+ var ORIGIN = /* @__PURE__ */ new WeakMap();
957
+ var LOCAL_CHANGES = /* @__PURE__ */ new WeakMap();
958
+ var CONNECTED = /* @__PURE__ */ new WeakSet();
959
+ var YjsEditor = {
960
+ isYjsEditor(value) {
961
+ return import_slate17.Editor.isEditor(value) && value.sharedRoot instanceof Y8.XmlText && "localOrigin" in value && "positionStorageOrigin" in value && typeof value.applyRemoteEvents === "function" && typeof value.storeLocalChange === "function" && typeof value.flushLocalChanges === "function" && typeof value.isLocalOrigin === "function" && typeof value.connect === "function" && typeof value.disconnect === "function";
962
+ },
963
+ localChanges(editor) {
964
+ var _a;
965
+ return (_a = LOCAL_CHANGES.get(editor)) != null ? _a : [];
966
+ },
967
+ applyRemoteEvents(editor, events, origin) {
968
+ editor.applyRemoteEvents(events, origin);
969
+ },
970
+ storeLocalChange(editor, op) {
971
+ editor.storeLocalChange(op);
972
+ },
973
+ flushLocalChanges(editor) {
974
+ editor.flushLocalChanges();
975
+ },
976
+ connected(editor) {
977
+ return CONNECTED.has(editor);
978
+ },
979
+ connect(editor) {
980
+ editor.connect();
981
+ },
982
+ disconnect(editor) {
983
+ editor.disconnect();
984
+ },
985
+ isLocal(editor) {
986
+ return editor.isLocalOrigin(YjsEditor.origin(editor));
987
+ },
988
+ origin(editor) {
989
+ const origin = ORIGIN.get(editor);
990
+ return origin !== void 0 ? origin : editor.localOrigin;
991
+ },
992
+ withOrigin(editor, origin, fn) {
993
+ const prev = YjsEditor.origin(editor);
994
+ ORIGIN.set(editor, origin);
995
+ fn();
996
+ ORIGIN.set(editor, prev);
997
+ },
998
+ storePosition(editor, key, point) {
999
+ const { sharedRoot, positionStorageOrigin: locationStorageOrigin } = editor;
1000
+ assertDocumentAttachment(sharedRoot);
1001
+ const position = slatePointToRelativePosition(sharedRoot, editor, point);
1002
+ sharedRoot.doc.transact(() => {
1003
+ setStoredPosition(sharedRoot, key, position);
1004
+ }, locationStorageOrigin);
1005
+ },
1006
+ removeStoredPosition(editor, key) {
1007
+ const { sharedRoot, positionStorageOrigin: locationStorageOrigin } = editor;
1008
+ assertDocumentAttachment(sharedRoot);
1009
+ sharedRoot.doc.transact(() => {
1010
+ removeStoredPosition(sharedRoot, key);
1011
+ }, locationStorageOrigin);
1012
+ },
1013
+ position(editor, key) {
1014
+ const position = getStoredPosition(editor.sharedRoot, key);
1015
+ if (!position) {
1016
+ return void 0;
1017
+ }
1018
+ return relativePositionToSlatePoint(editor.sharedRoot, editor, position);
1019
+ },
1020
+ storedPositionsRelative(editor) {
1021
+ return getStoredPositions(editor.sharedRoot);
1022
+ }
1023
+ };
1024
+ function withYjs(editor, sharedRoot, {
1025
+ localOrigin,
1026
+ positionStorageOrigin,
1027
+ autoConnect = false
1028
+ } = {}) {
1029
+ const e = editor;
1030
+ e.sharedRoot = sharedRoot;
1031
+ e.localOrigin = localOrigin != null ? localOrigin : DEFAULT_LOCAL_ORIGIN;
1032
+ e.positionStorageOrigin = positionStorageOrigin != null ? positionStorageOrigin : DEFAULT_POSITION_STORAGE_ORIGIN;
1033
+ e.applyRemoteEvents = (events, origin) => {
1034
+ YjsEditor.flushLocalChanges(e);
1035
+ import_slate17.Editor.withoutNormalizing(e, () => {
1036
+ YjsEditor.withOrigin(e, origin, () => {
1037
+ applyYjsEvents(e.sharedRoot, e, events);
1038
+ });
1039
+ });
1040
+ };
1041
+ e.isLocalOrigin = (origin) => origin === e.localOrigin;
1042
+ const handleYEvents = (events, transaction) => {
1043
+ if (e.isLocalOrigin(transaction.origin)) {
1044
+ return;
1045
+ }
1046
+ YjsEditor.applyRemoteEvents(e, events, transaction.origin);
1047
+ };
1048
+ let autoConnectTimeoutId = null;
1049
+ if (autoConnect) {
1050
+ autoConnectTimeoutId = setTimeout(() => {
1051
+ autoConnectTimeoutId = null;
1052
+ YjsEditor.connect(e);
1053
+ });
1054
+ }
1055
+ e.connect = () => {
1056
+ if (YjsEditor.connected(e)) {
1057
+ throw new Error("already connected");
1058
+ }
1059
+ e.sharedRoot.observeDeep(handleYEvents);
1060
+ const content = yTextToSlateElement(e.sharedRoot);
1061
+ e.children = content.children;
1062
+ CONNECTED.add(e);
1063
+ import_slate17.Editor.normalize(editor, { force: true });
1064
+ if (!editor.operations.length) {
1065
+ editor.onChange();
1066
+ }
1067
+ };
1068
+ e.disconnect = () => {
1069
+ if (autoConnectTimeoutId) {
1070
+ clearTimeout(autoConnectTimeoutId);
1071
+ }
1072
+ YjsEditor.flushLocalChanges(e);
1073
+ e.sharedRoot.unobserveDeep(handleYEvents);
1074
+ CONNECTED.delete(e);
1075
+ };
1076
+ e.storeLocalChange = (op) => {
1077
+ LOCAL_CHANGES.set(e, [
1078
+ ...YjsEditor.localChanges(e),
1079
+ { op, doc: editor.children, origin: YjsEditor.origin(e) }
1080
+ ]);
1081
+ };
1082
+ e.flushLocalChanges = () => {
1083
+ assertDocumentAttachment(e.sharedRoot);
1084
+ const localChanges = YjsEditor.localChanges(e);
1085
+ LOCAL_CHANGES.delete(e);
1086
+ const txGroups = [];
1087
+ localChanges.forEach((change) => {
1088
+ const currentGroup = txGroups[txGroups.length - 1];
1089
+ if (currentGroup && currentGroup[0].origin === change.origin) {
1090
+ return currentGroup.push(change);
1091
+ }
1092
+ txGroups.push([change]);
1093
+ });
1094
+ txGroups.forEach((txGroup) => {
1095
+ assertDocumentAttachment(e.sharedRoot);
1096
+ e.sharedRoot.doc.transact(() => {
1097
+ txGroup.forEach((change) => {
1098
+ assertDocumentAttachment(e.sharedRoot);
1099
+ applySlateOp(e.sharedRoot, { children: change.doc }, change.op);
1100
+ });
1101
+ }, txGroup[0].origin);
1102
+ });
1103
+ };
1104
+ const { apply, onChange } = e;
1105
+ e.apply = (op) => {
1106
+ if (YjsEditor.connected(e) && YjsEditor.isLocal(e)) {
1107
+ YjsEditor.storeLocalChange(e, op);
1108
+ }
1109
+ apply(op);
1110
+ };
1111
+ e.onChange = () => {
1112
+ if (YjsEditor.connected(e)) {
1113
+ YjsEditor.flushLocalChanges(e);
1114
+ }
1115
+ onChange();
1116
+ };
1117
+ return e;
1118
+ }
1119
+
1120
+ // src/plugins/withYHistory.ts
1121
+ var import_slate18 = require("slate");
1122
+ var Y9 = __toESM(require("yjs"), 1);
1123
+ var LAST_SELECTION = /* @__PURE__ */ new WeakMap();
1124
+ var DEFAULT_WITHOUT_SAVING_ORIGIN = Symbol("slate-yjs-history-without-saving");
1125
+ var YHistoryEditor = {
1126
+ isYHistoryEditor(value) {
1127
+ return YjsEditor.isYjsEditor(value) && value.undoManager instanceof Y9.UndoManager && typeof value.undo === "function" && typeof value.redo === "function" && "withoutSavingOrigin" in value;
1128
+ },
1129
+ canUndo(editor) {
1130
+ return editor.undoManager.undoStack.length > 0;
1131
+ },
1132
+ canRedo(editor) {
1133
+ return editor.undoManager.redoStack.length > 0;
1134
+ },
1135
+ isSaving(editor) {
1136
+ return editor.undoManager.trackedOrigins.has(YjsEditor.origin(editor));
1137
+ },
1138
+ withoutSaving(editor, fn) {
1139
+ YjsEditor.withOrigin(editor, editor.withoutSavingOrigin, fn);
1140
+ }
1141
+ };
1142
+ function withYHistory(editor, _a = {}) {
1143
+ var _b = _a, {
1144
+ withoutSavingOrigin = DEFAULT_WITHOUT_SAVING_ORIGIN,
1145
+ trackedOrigins = /* @__PURE__ */ new Set([editor.localOrigin])
1146
+ } = _b, options = __objRest(_b, [
1147
+ "withoutSavingOrigin",
1148
+ "trackedOrigins"
1149
+ ]);
1150
+ const e = editor;
1151
+ const undoManager = new Y9.UndoManager(e.sharedRoot, __spreadValues({
1152
+ trackedOrigins
1153
+ }, options));
1154
+ e.undoManager = undoManager;
1155
+ e.withoutSavingOrigin = withoutSavingOrigin;
1156
+ const { onChange, isLocalOrigin } = e;
1157
+ e.onChange = () => {
1158
+ onChange();
1159
+ LAST_SELECTION.set(e, e.selection && slateRangeToRelativeRange(e.sharedRoot, e, e.selection));
1160
+ };
1161
+ e.isLocalOrigin = (origin) => origin === e.withoutSavingOrigin || isLocalOrigin(origin);
1162
+ const handleStackItemAdded = ({
1163
+ stackItem
1164
+ }) => {
1165
+ stackItem.meta.set("selection", e.selection && slateRangeToRelativeRange(e.sharedRoot, e, e.selection));
1166
+ stackItem.meta.set("selectionBefore", LAST_SELECTION.get(e));
1167
+ };
1168
+ const handleStackItemUpdated = ({
1169
+ stackItem
1170
+ }) => {
1171
+ stackItem.meta.set("selection", e.selection && slateRangeToRelativeRange(e.sharedRoot, e, e.selection));
1172
+ };
1173
+ const handleStackItemPopped = ({
1174
+ stackItem,
1175
+ type
1176
+ }) => {
1177
+ const inverseStack = type === "undo" ? e.undoManager.redoStack : e.undoManager.undoStack;
1178
+ const inverseItem = inverseStack[inverseStack.length - 1];
1179
+ if (inverseItem) {
1180
+ inverseItem.meta.set("selection", stackItem.meta.get("selectionBefore"));
1181
+ inverseItem.meta.set("selectionBefore", stackItem.meta.get("selection"));
1182
+ }
1183
+ const relativeSelection = stackItem.meta.get("selectionBefore");
1184
+ if (!relativeSelection) {
1185
+ return;
1186
+ }
1187
+ const selection = relativeRangeToSlateRange(e.sharedRoot, e, relativeSelection);
1188
+ if (!selection) {
1189
+ return;
1190
+ }
1191
+ import_slate18.Transforms.select(e, selection);
1192
+ };
1193
+ const { connect, disconnect } = e;
1194
+ e.connect = () => {
1195
+ connect();
1196
+ e.undoManager.on("stack-item-added", handleStackItemAdded);
1197
+ e.undoManager.on("stack-item-popped", handleStackItemPopped);
1198
+ e.undoManager.on("stack-item-updated", handleStackItemUpdated);
1199
+ };
1200
+ e.disconnect = () => {
1201
+ e.undoManager.off("stack-item-added", handleStackItemAdded);
1202
+ e.undoManager.off("stack-item-popped", handleStackItemPopped);
1203
+ e.undoManager.off("stack-item-updated", handleStackItemUpdated);
1204
+ disconnect();
1205
+ };
1206
+ e.undo = () => {
1207
+ if (YjsEditor.connected(e)) {
1208
+ YjsEditor.flushLocalChanges(e);
1209
+ e.undoManager.undo();
1210
+ }
1211
+ };
1212
+ e.redo = () => {
1213
+ if (YjsEditor.connected(e)) {
1214
+ YjsEditor.flushLocalChanges(e);
1215
+ e.undoManager.redo();
1216
+ }
1217
+ };
1218
+ return e;
1219
+ }
1220
+
1221
+ // src/plugins/withCursors.ts
1222
+ var Y10 = __toESM(require("yjs"), 1);
1223
+ var CURSOR_CHANGE_EVENT_LISTENERS = /* @__PURE__ */ new WeakMap();
1224
+ var CursorEditor = {
1225
+ isCursorEditor(value) {
1226
+ return YjsEditor.isYjsEditor(value) && value.awareness && typeof value.cursorDataField === "string" && typeof value.selectionStateField === "string" && typeof value.sendCursorPosition === "function" && typeof value.sendCursorData === "function";
1227
+ },
1228
+ sendCursorPosition(editor, range = editor.selection) {
1229
+ editor.sendCursorPosition(range);
1230
+ },
1231
+ sendCursorData(editor, data) {
1232
+ editor.sendCursorData(data);
1233
+ },
1234
+ on(editor, event, handler) {
1235
+ var _a;
1236
+ if (event !== "change") {
1237
+ return;
1238
+ }
1239
+ const listeners = (_a = CURSOR_CHANGE_EVENT_LISTENERS.get(editor)) != null ? _a : /* @__PURE__ */ new Set();
1240
+ listeners.add(handler);
1241
+ CURSOR_CHANGE_EVENT_LISTENERS.set(editor, listeners);
1242
+ },
1243
+ off(editor, event, listener) {
1244
+ if (event !== "change") {
1245
+ return;
1246
+ }
1247
+ const listeners = CURSOR_CHANGE_EVENT_LISTENERS.get(editor);
1248
+ if (listeners) {
1249
+ listeners.delete(listener);
1250
+ }
1251
+ },
1252
+ cursorState(editor, clientId) {
1253
+ var _a;
1254
+ if (clientId === editor.awareness.clientID || !YjsEditor.connected(editor)) {
1255
+ return null;
1256
+ }
1257
+ const state = editor.awareness.getStates().get(clientId);
1258
+ if (!state) {
1259
+ return null;
1260
+ }
1261
+ return {
1262
+ relativeSelection: (_a = state[editor.selectionStateField]) != null ? _a : null,
1263
+ data: state[editor.cursorDataField],
1264
+ clientId
1265
+ };
1266
+ },
1267
+ cursorStates(editor) {
1268
+ if (!YjsEditor.connected(editor)) {
1269
+ return {};
1270
+ }
1271
+ return Object.fromEntries(Array.from(editor.awareness.getStates().entries(), ([id, state]) => {
1272
+ if (id === editor.awareness.clientID || !state) {
1273
+ return null;
1274
+ }
1275
+ return [
1276
+ id,
1277
+ {
1278
+ relativeSelection: state[editor.selectionStateField],
1279
+ data: state[editor.cursorDataField]
1280
+ }
1281
+ ];
1282
+ }).filter(Array.isArray));
1283
+ }
1284
+ };
1285
+ function withCursors(editor, awareness, {
1286
+ cursorStateField: selectionStateField = "selection",
1287
+ cursorDataField = "data",
1288
+ autoSend = true,
1289
+ data
1290
+ } = {}) {
1291
+ const e = editor;
1292
+ e.awareness = awareness;
1293
+ e.cursorDataField = cursorDataField;
1294
+ e.selectionStateField = selectionStateField;
1295
+ e.sendCursorData = (cursorData) => {
1296
+ e.awareness.setLocalStateField(e.cursorDataField, cursorData);
1297
+ };
1298
+ e.sendCursorPosition = (range) => {
1299
+ const localState = e.awareness.getLocalState();
1300
+ const currentRange = localState == null ? void 0 : localState[selectionStateField];
1301
+ if (!range) {
1302
+ if (currentRange) {
1303
+ e.awareness.setLocalStateField(e.selectionStateField, null);
1304
+ }
1305
+ return;
1306
+ }
1307
+ const { anchor, focus } = slateRangeToRelativeRange(e.sharedRoot, e, range);
1308
+ if (!currentRange || !Y10.compareRelativePositions(anchor, currentRange) || !Y10.compareRelativePositions(focus, currentRange)) {
1309
+ e.awareness.setLocalStateField(e.selectionStateField, { anchor, focus });
1310
+ }
1311
+ };
1312
+ const awarenessChangeListener = (yEvent) => {
1313
+ const listeners = CURSOR_CHANGE_EVENT_LISTENERS.get(e);
1314
+ if (!listeners) {
1315
+ return;
1316
+ }
1317
+ const localId = e.awareness.clientID;
1318
+ const event = {
1319
+ added: yEvent.added.filter((id) => id !== localId),
1320
+ removed: yEvent.removed.filter((id) => id !== localId),
1321
+ updated: yEvent.updated.filter((id) => id !== localId)
1322
+ };
1323
+ if (event.added.length > 0 || event.removed.length > 0 || event.updated.length > 0) {
1324
+ listeners.forEach((listener) => listener(event));
1325
+ }
1326
+ };
1327
+ const { connect, disconnect } = e;
1328
+ e.connect = () => {
1329
+ connect();
1330
+ e.awareness.on("change", awarenessChangeListener);
1331
+ awarenessChangeListener({
1332
+ removed: [],
1333
+ added: Array.from(e.awareness.getStates().keys()),
1334
+ updated: []
1335
+ });
1336
+ if (autoSend) {
1337
+ if (data) {
1338
+ CursorEditor.sendCursorData(e, data);
1339
+ }
1340
+ const { onChange } = e;
1341
+ e.onChange = () => {
1342
+ onChange();
1343
+ if (YjsEditor.connected(e)) {
1344
+ CursorEditor.sendCursorPosition(e);
1345
+ }
1346
+ };
1347
+ }
1348
+ };
1349
+ e.disconnect = () => {
1350
+ e.awareness.off("change", awarenessChangeListener);
1351
+ awarenessChangeListener({
1352
+ removed: Array.from(e.awareness.getStates().keys()),
1353
+ added: [],
1354
+ updated: []
1355
+ });
1356
+ disconnect();
1357
+ };
1358
+ return e;
1359
+ }
1360
+ //# sourceMappingURL=index.cjs.map