edytor 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +225 -5
  2. package/dist/block/block.svelte.d.ts +123 -0
  3. package/dist/block/block.svelte.js +430 -0
  4. package/dist/block/block.utils.d.ts +82 -0
  5. package/dist/block/block.utils.js +499 -0
  6. package/dist/block/content.svelte.d.ts +14 -0
  7. package/dist/block/content.svelte.js +40 -0
  8. package/dist/block/inlineBlock.svelte.d.ts +30 -0
  9. package/dist/block/inlineBlock.svelte.js +53 -0
  10. package/dist/components/Block.svelte +27 -0
  11. package/dist/components/Block.svelte.d.ts +7 -0
  12. package/dist/components/Content.svelte +44 -0
  13. package/dist/components/Content.svelte.d.ts +7 -0
  14. package/dist/components/Edytor.svelte +165 -0
  15. package/dist/components/Edytor.svelte.d.ts +33 -0
  16. package/dist/components/InlineBlock.svelte +17 -0
  17. package/dist/components/InlineBlock.svelte.d.ts +7 -0
  18. package/dist/components/Mark.svelte +38 -0
  19. package/dist/components/Mark.svelte.d.ts +11 -0
  20. package/dist/components/ReadonlyEditor.svelte +46 -0
  21. package/dist/components/ReadonlyEditor.svelte.d.ts +4 -0
  22. package/dist/components/Text.svelte +37 -0
  23. package/dist/components/Text.svelte.d.ts +7 -0
  24. package/dist/components/readonlyElements.svelte.d.ts +82 -0
  25. package/dist/components/readonlyElements.svelte.js +144 -0
  26. package/dist/constants.d.ts +4 -0
  27. package/dist/constants.js +4 -0
  28. package/dist/dnd.svelte.d.ts +17 -0
  29. package/dist/dnd.svelte.js +125 -0
  30. package/dist/edytor.svelte.d.ts +94 -0
  31. package/dist/edytor.svelte.js +262 -0
  32. package/dist/edytor.utils.d.ts +3 -0
  33. package/dist/edytor.utils.js +78 -0
  34. package/dist/events/onBeforeInput.d.ts +2 -2
  35. package/dist/events/onBeforeInput.js +338 -0
  36. package/dist/events/onKeyDown.d.ts +2 -69
  37. package/dist/events/onKeyDown.js +18 -0
  38. package/dist/hotkeys.d.ts +27 -0
  39. package/dist/hotkeys.js +282 -0
  40. package/dist/index.d.ts +7 -5
  41. package/dist/index.js +7 -8
  42. package/dist/localProvider.d.ts +82 -0
  43. package/dist/localProvider.js +267 -0
  44. package/dist/plugins/arrowMove/arrowMove.d.ts +2 -0
  45. package/dist/plugins/arrowMove/arrowMove.js +66 -0
  46. package/dist/plugins/code/CodePlugin.svelte +218 -0
  47. package/dist/plugins/code/CodePlugin.svelte.d.ts +23 -0
  48. package/dist/plugins/code/prism.css +141 -0
  49. package/dist/plugins/image/ImagePlugin.svelte +22 -0
  50. package/dist/plugins/image/ImagePlugin.svelte.d.ts +20 -0
  51. package/dist/plugins/index.d.ts +3 -0
  52. package/dist/plugins/index.js +3 -0
  53. package/dist/plugins/mention/MentionPlugin.svelte +40 -0
  54. package/dist/plugins/mention/MentionPlugin.svelte.d.ts +20 -0
  55. package/dist/plugins/richtext/RichTextPlugin.svelte +241 -0
  56. package/dist/plugins/richtext/RichTextPlugin.svelte.d.ts +26 -0
  57. package/dist/plugins.d.ts +202 -0
  58. package/dist/plugins.js +19 -0
  59. package/dist/selection/selection.svelte.d.ts +68 -0
  60. package/dist/selection/selection.svelte.js +391 -0
  61. package/dist/selection/selection.utils.d.ts +14 -0
  62. package/dist/selection/selection.utils.js +153 -0
  63. package/dist/text/deltas.d.ts +11 -0
  64. package/dist/text/deltas.js +109 -0
  65. package/dist/text/text.svelte.d.ts +70 -0
  66. package/dist/text/text.svelte.js +119 -0
  67. package/dist/text/text.utils.d.ts +40 -0
  68. package/dist/text/text.utils.js +174 -0
  69. package/dist/utils/json.d.ts +32 -0
  70. package/dist/utils/json.js +2 -0
  71. package/dist/utils/jsx.d.ts +25 -0
  72. package/dist/utils/jsx.js +66 -0
  73. package/dist/utils/serialize.d.ts +1 -0
  74. package/dist/utils/serialize.js +1 -0
  75. package/dist/utils.d.ts +6 -0
  76. package/dist/utils.js +19 -0
  77. package/package.json +81 -33
  78. package/dist/edytor.cjs.development.js +0 -1762
  79. package/dist/edytor.cjs.development.js.map +0 -1
  80. package/dist/edytor.cjs.production.min.js +0 -2
  81. package/dist/edytor.cjs.production.min.js.map +0 -1
  82. package/dist/edytor.esm.js +0 -1691
  83. package/dist/edytor.esm.js.map +0 -1
  84. package/dist/events/index.d.ts +0 -3
  85. package/dist/events/onDrop.d.ts +0 -3
  86. package/dist/operations/deleteText.d.ts +0 -7
  87. package/dist/operations/formatText.d.ts +0 -20
  88. package/dist/operations/index.d.ts +0 -9
  89. package/dist/operations/insertText.d.ts +0 -5
  90. package/dist/operations/merge.d.ts +0 -3
  91. package/dist/operations/moveNode.d.ts +0 -12
  92. package/dist/operations/nestNode.d.ts +0 -2
  93. package/dist/operations/removeEmptyText.d.ts +0 -2
  94. package/dist/operations/splitLeaf.d.ts +0 -2
  95. package/dist/operations/splitNode.d.ts +0 -9
  96. package/dist/types.d.ts +0 -140
  97. package/dist/utils/common.d.ts +0 -17
  98. package/dist/utils/dropper.d.ts +0 -26
  99. package/dist/utils/index.d.ts +0 -6
  100. package/dist/utils/leaves.d.ts +0 -34
  101. package/dist/utils/nodes.d.ts +0 -14
  102. package/dist/utils/selection.d.ts +0 -51
  103. package/dist/utils/yClasses/EdytorDoc.d.ts +0 -16
  104. package/dist/utils/yClasses/index.d.ts +0 -3
  105. package/dist/utils/yClasses/yLeaf.d.ts +0 -7
  106. package/dist/utils/yClasses/yNode.d.ts +0 -12
  107. package/dist/yjs/index.d.ts +0 -1
  108. package/dist/yjs/wsProvider.d.ts +0 -1
  109. package/index.ts +0 -1
@@ -0,0 +1,499 @@
1
+ import { Block } from './block.svelte.js';
2
+ import { Text } from '../text/text.svelte.js';
3
+ import { prevent } from '../utils.js';
4
+ import { InlineBlock } from './inlineBlock.svelte.js';
5
+ import * as Y from 'yjs';
6
+ export function batch(operation, func) {
7
+ return function (payload) {
8
+ let finalPayload = payload;
9
+ for (const plugin of this.edytor.plugins) {
10
+ // @ts-expect-error
11
+ const normalizedPayload = plugin.onBeforeOperation?.({
12
+ operation,
13
+ payload,
14
+ block: this,
15
+ prevent
16
+ });
17
+ if (normalizedPayload) {
18
+ finalPayload = normalizedPayload;
19
+ break;
20
+ }
21
+ }
22
+ const result = this.edytor.transact(() => func.bind(this)(finalPayload));
23
+ for (const plugin of this.edytor.plugins) {
24
+ plugin.onAfterOperation?.({
25
+ operation,
26
+ payload,
27
+ block: this
28
+ });
29
+ }
30
+ return result;
31
+ };
32
+ }
33
+ export function addChildBlock({ block, index = this.yChildren.length }) {
34
+ const newBlock = new Block({ parent: this, edytor: this.edytor, block });
35
+ this.yChildren.insert(index, [newBlock.yBlock]);
36
+ return newBlock;
37
+ }
38
+ export function addChildBlocks({ blocks, index = this.yChildren.length }) {
39
+ const newBlocks = blocks.map((block) => new Block({ parent: this, edytor: this.edytor, block }));
40
+ this.yChildren.insert(index, newBlocks.map((block) => block.yBlock));
41
+ return newBlocks;
42
+ }
43
+ export function insertBlockAfter({ block }) {
44
+ if (!this.parent) {
45
+ return null;
46
+ }
47
+ this.yChildren.delete(0, this.children.length);
48
+ return this.parent.addChildBlock({
49
+ block: {
50
+ ...block,
51
+ children: this.value.children
52
+ },
53
+ index: this.index + 1
54
+ });
55
+ }
56
+ export function insertBlockBefore({ block }) {
57
+ if (!this.parent) {
58
+ return null;
59
+ }
60
+ return this.parent.addChildBlock({
61
+ block: {
62
+ ...block,
63
+ children: this.value.children
64
+ },
65
+ index: this.index
66
+ });
67
+ }
68
+ export function splitBlock({ index, text }) {
69
+ if (!text || !this.parent) {
70
+ return null;
71
+ }
72
+ const splittedContent = text.splitText({ index });
73
+ const indexOfContent = this.content.indexOf(text);
74
+ const remainingContent = this.content.slice(indexOfContent + 1).map((part) => part.value);
75
+ const content = [splittedContent, ...remainingContent].flat();
76
+ const hasChildren = this.children.length >= 1;
77
+ // Add the current children to the new block if any
78
+ this.yContent.delete(indexOfContent + 1, this.content.length - indexOfContent - 1);
79
+ const newBlock = this.parent.addChildBlock({
80
+ block: {
81
+ type: this.edytor.getDefaultBlock(this.parent),
82
+ content,
83
+ children: this.value.children
84
+ },
85
+ index: this.parent.children.indexOf(this) + 1
86
+ });
87
+ // If the block has children, we need to remove its children and insert them into the new block
88
+ if (hasChildren) {
89
+ this.yChildren.delete(0, this.children.length);
90
+ }
91
+ return newBlock;
92
+ }
93
+ export function removeBlock({ keepChildren = false } = { keepChildren: false }) {
94
+ if (!this.parent) {
95
+ return;
96
+ }
97
+ // Get the current index from yChildren array since this.index may be stale when removing multiple blocks at once
98
+ const index = this.parent.yChildren.toArray().indexOf(this.yBlock);
99
+ if (this.yBlock._item?.deleted) {
100
+ return;
101
+ }
102
+ this.parent.yChildren.delete(index, 1);
103
+ if (keepChildren && this.hasChildren) {
104
+ this.parent.yChildren.insert(this.index, this.value.children.map((child) => {
105
+ const newBlock = new Block({
106
+ parent: this.parent,
107
+ edytor: this.edytor,
108
+ block: child
109
+ });
110
+ return newBlock.yBlock;
111
+ }));
112
+ }
113
+ }
114
+ export function mergeBlockBackward() {
115
+ if (!this.parent) {
116
+ return null;
117
+ }
118
+ const { closestPreviousBlock, isEmpty } = this;
119
+ const { children = [] } = this.value;
120
+ if (!closestPreviousBlock) {
121
+ return this.isEmpty ? this.mergeBlockForward() : null;
122
+ }
123
+ // Add the current content to the previous block content
124
+ closestPreviousBlock.pushContentIntoBlock({ value: this.content });
125
+ if (!isEmpty) {
126
+ // If the current block has children, we need to unnest them and insert them into the current parent
127
+ if (children.length > 0) {
128
+ // Unnest children if any
129
+ this.parent.yChildren.insert(this.index, children.map((child) => {
130
+ const newBlock = new Block({
131
+ parent: this.parent,
132
+ edytor: this.edytor,
133
+ block: child
134
+ });
135
+ return newBlock.yBlock;
136
+ }));
137
+ }
138
+ }
139
+ // Remove the current block from its position
140
+ this.parent.yChildren.delete(this.index + this.children.length, 1);
141
+ return closestPreviousBlock;
142
+ }
143
+ export function mergeBlockForward() {
144
+ if (!this.parent) {
145
+ return null;
146
+ }
147
+ const nextBlock = this.closestNextBlock;
148
+ if (!nextBlock) {
149
+ return null;
150
+ }
151
+ this.pushContentIntoBlock({ value: nextBlock.content });
152
+ if (nextBlock.children.length > 0 && nextBlock.parent) {
153
+ nextBlock.parent.yChildren.insert(nextBlock.index + 1, nextBlock.children.map((child) => {
154
+ const newBlock = new Block({
155
+ parent: nextBlock.parent,
156
+ edytor: this.edytor,
157
+ block: child.value
158
+ });
159
+ return newBlock.yBlock;
160
+ }));
161
+ }
162
+ nextBlock.parent?.yChildren.delete(nextBlock.index, 1);
163
+ return nextBlock;
164
+ }
165
+ export function moveBlock({ path }) {
166
+ if (!path.length || path.some((p) => isNaN(p) || p < 0) || !this.parent) {
167
+ return null;
168
+ }
169
+ const lastIndex = path.pop();
170
+ let currentBlock = this.edytor.root;
171
+ while (path.length > 0) {
172
+ const index = path.shift();
173
+ if (typeof index !== 'number' || isNaN(index))
174
+ break;
175
+ currentBlock = currentBlock.children[index];
176
+ }
177
+ if (!currentBlock) {
178
+ return null;
179
+ }
180
+ this.edytor.idToBlock.delete(this.id);
181
+ this.parent.yChildren.delete(this.index, 1);
182
+ const newBlock = new Block({
183
+ parent: currentBlock,
184
+ edytor: this.edytor,
185
+ block: this.value
186
+ });
187
+ currentBlock.yChildren.insert(lastIndex, [newBlock.yBlock]);
188
+ return newBlock;
189
+ }
190
+ export function unNestBlock() {
191
+ const { parent, index } = this;
192
+ if (!parent) {
193
+ return null;
194
+ }
195
+ const grandParent = parent.parent;
196
+ if (!grandParent) {
197
+ return null;
198
+ }
199
+ const newBlock = new Block({
200
+ parent: grandParent,
201
+ edytor: this.edytor,
202
+ block: this.value
203
+ });
204
+ grandParent.yChildren.insert(parent.index + 1, [newBlock.yBlock]);
205
+ parent.yChildren.delete(index, 1);
206
+ return newBlock;
207
+ }
208
+ export function nestBlock() {
209
+ const previousBlock = this.previousBlock;
210
+ if (!previousBlock ||
211
+ previousBlock?.definition?.void ||
212
+ previousBlock?.definition?.island ||
213
+ !this.parent) {
214
+ return null;
215
+ }
216
+ const newBlock = new Block({
217
+ parent: previousBlock,
218
+ edytor: this.edytor,
219
+ block: { ...this.value, children: [] }
220
+ });
221
+ previousBlock.yChildren.insert(previousBlock.children.length, [newBlock.yBlock]);
222
+ if (this.value.children && this.value.children.length) {
223
+ previousBlock.yChildren.insert(previousBlock.children.length + 1, this.value.children.map((child) => {
224
+ const newBlock = new Block({
225
+ parent: previousBlock,
226
+ edytor: this.edytor,
227
+ block: child
228
+ });
229
+ return newBlock.yBlock;
230
+ }));
231
+ }
232
+ this.parent.yChildren.delete(this.index, 1);
233
+ return newBlock;
234
+ }
235
+ export function setBlock({ value }) {
236
+ this.edytor.doc.transact(() => {
237
+ if (value.type) {
238
+ this.type = value.type;
239
+ }
240
+ if (value.data) {
241
+ this.yBlock.set('data', value.data);
242
+ }
243
+ if (value.content) {
244
+ let newContentCount = value.content.length;
245
+ let oldContentCount = this.content.length;
246
+ const contentToRemove = oldContentCount - newContentCount;
247
+ contentToRemove && this.yContent.delete(newContentCount, contentToRemove);
248
+ const groupedContent = groupContent(value.content);
249
+ this.yContent.insert(0, groupedContent.map((part) => {
250
+ if ('type' in part) {
251
+ const newInlineBlock = new InlineBlock({
252
+ parent: this,
253
+ block: part
254
+ });
255
+ return newInlineBlock.yBlock;
256
+ }
257
+ else {
258
+ const newText = new Text({
259
+ parent: this,
260
+ content: part
261
+ });
262
+ return newText.yText;
263
+ }
264
+ }));
265
+ }
266
+ else {
267
+ this.yContent.delete(0, this.content.length);
268
+ }
269
+ if (value.children) {
270
+ let newChildrenCount = value.children.length;
271
+ let oldChildrenCount = this.children.length;
272
+ const childrenToRemove = oldChildrenCount - newChildrenCount;
273
+ this.children = value.children.map((child, i) => {
274
+ const existingChild = this.children[i];
275
+ if (existingChild) {
276
+ existingChild.setBlock({ value: child });
277
+ return existingChild;
278
+ }
279
+ else {
280
+ return this.addChildBlock({ block: child, index: i });
281
+ }
282
+ });
283
+ childrenToRemove && this.yChildren.delete(newChildrenCount, childrenToRemove);
284
+ }
285
+ else {
286
+ this.yChildren.delete(0, this.children.length);
287
+ }
288
+ });
289
+ }
290
+ export function pushContentIntoBlock({ value }) {
291
+ const content = this.content.filter((part) => part instanceof Text ? !part.yText._item?.deleted : !part.yBlock._item?.deleted);
292
+ let index = content.length;
293
+ for (const part of value) {
294
+ if (part instanceof InlineBlock) {
295
+ // is an inline block needed to be added
296
+ const newInlineBlock = new InlineBlock({
297
+ parent: this,
298
+ block: part
299
+ });
300
+ this.yContent.insert(index, [newInlineBlock.yBlock]);
301
+ index++;
302
+ }
303
+ else {
304
+ const lastPart = content[index - 1];
305
+ if (lastPart instanceof Text) {
306
+ const delta = part.yText.toDelta();
307
+ lastPart.yText.applyDelta([{ retain: lastPart.yText.length }, ...delta]);
308
+ }
309
+ else {
310
+ const newText = new Text({
311
+ parent: this,
312
+ content: part.value
313
+ });
314
+ this.yContent.insert(index, [newText.yText]);
315
+ index++;
316
+ }
317
+ }
318
+ }
319
+ console.log(this.yContent.toArray());
320
+ }
321
+ export function removeInlineBlock({ index }) {
322
+ const part = this.content.at(index);
323
+ if (part && part instanceof InlineBlock) {
324
+ this.yContent.delete(index, 1);
325
+ this.normalizeContent();
326
+ }
327
+ }
328
+ export const groupContent = (content) => {
329
+ const isInlineJSONBlock = (part) => {
330
+ return part ? 'type' in part : false;
331
+ };
332
+ // this function group JSONBlock.content texts together in order to avoid having successive inline Y.Text as it would be ineficient.
333
+ if (!content)
334
+ return [[{ text: '' }]];
335
+ const groupedContent = content.reduce((acc, part) => {
336
+ const isInlineBlock = 'type' in part;
337
+ if (isInlineBlock) {
338
+ if (isInlineJSONBlock(acc.at(-1))) {
339
+ // Make sure that two consecutive inline blocks are separated by a text block
340
+ acc.push([{ text: '' }]);
341
+ }
342
+ acc.push(part);
343
+ }
344
+ else {
345
+ const lastPart = acc.at(-1);
346
+ if (acc.length && lastPart && Array.isArray(lastPart)) {
347
+ lastPart.push(part);
348
+ }
349
+ else {
350
+ acc.push([part]);
351
+ }
352
+ }
353
+ return acc;
354
+ }, []);
355
+ if (isInlineJSONBlock(groupedContent.at(0))) {
356
+ // Make sure that the first part is an inline block
357
+ groupedContent.unshift([{ text: '' }]);
358
+ }
359
+ if (isInlineJSONBlock(groupedContent.at(-1))) {
360
+ // Make sure that the last part is a text block
361
+ groupedContent.push([{ text: '' }]);
362
+ }
363
+ return groupedContent;
364
+ };
365
+ export function addInlineBlock({ index, block, text }) {
366
+ // TODO
367
+ const newInlineBlock = new InlineBlock({
368
+ parent: this,
369
+ block
370
+ });
371
+ const newText = new Text({
372
+ parent: this,
373
+ content: text.splitText({ index })
374
+ });
375
+ this.yContent.insert(text.index + 1, [newInlineBlock.yBlock, newText.yText]);
376
+ this.normalizeContent();
377
+ return newText;
378
+ }
379
+ export function normalizeContent() {
380
+ const content = this.yContent.toArray().filter((part) => !part._item?.deleted);
381
+ // Ensure content starts with Text
382
+ if (content.length === 0 || !(content[0] instanceof Y.Text)) {
383
+ const emptyText = new Text({
384
+ parent: this,
385
+ content: [{ text: '' }]
386
+ });
387
+ this.yContent.insert(0, [emptyText.yText]);
388
+ return this.normalizeContent();
389
+ }
390
+ // Ensure content ends with Text
391
+ if (!(content[content.length - 1] instanceof Y.Text)) {
392
+ const emptyText = new Text({
393
+ parent: this,
394
+ content: [{ text: '' }]
395
+ });
396
+ this.yContent.insert(content.length, [emptyText.yText]);
397
+ return this.normalizeContent();
398
+ }
399
+ // First handle consecutive text blocks
400
+ const consecutiveTexts = content.reduce((acc, part, index) => {
401
+ const nextPart = content[index + 1];
402
+ if (part instanceof Y.Text && nextPart instanceof Y.Text) {
403
+ acc.push([part, nextPart]);
404
+ }
405
+ return acc;
406
+ }, []);
407
+ if (consecutiveTexts.length > 0) {
408
+ const [first, second] = consecutiveTexts[0];
409
+ const delta = second.toDelta();
410
+ first.applyDelta([{ retain: first.length }, ...delta]);
411
+ this.yContent.delete(content.indexOf(second), 1);
412
+ return this.normalizeContent();
413
+ }
414
+ // Then handle consecutive inline blocks
415
+ const consecutiveInlineBlocks = content.reduce((acc, part, index) => {
416
+ const nextPart = content[index + 1];
417
+ if (part instanceof Y.Map && nextPart instanceof Y.Map) {
418
+ acc.push([part, nextPart]);
419
+ }
420
+ return acc;
421
+ }, []);
422
+ if (consecutiveInlineBlocks.length > 0) {
423
+ const [first, second] = consecutiveInlineBlocks[0];
424
+ const emptyText = new Text({
425
+ parent: this,
426
+ content: [{ text: '' }]
427
+ });
428
+ const index = content.indexOf(second);
429
+ this.yContent.insert(index, [emptyText.yText]);
430
+ return this.normalizeContent();
431
+ }
432
+ const pluginNormalization = this.definition?.normalizeContent?.({ block: this });
433
+ if (pluginNormalization) {
434
+ pluginNormalization();
435
+ this.normalizeContent();
436
+ }
437
+ }
438
+ export function suggestText({ value }) {
439
+ if (typeof value === 'string') {
440
+ this.suggestions = [[{ text: value }]];
441
+ }
442
+ else if (value) {
443
+ this.suggestions = groupContent(value);
444
+ }
445
+ else {
446
+ this.suggestions = null;
447
+ }
448
+ }
449
+ export function acceptSuggestedText() {
450
+ if (!this.suggestions) {
451
+ return;
452
+ }
453
+ const editableSuggestions = this.suggestions.map((part) => {
454
+ if ('type' in part) {
455
+ return new InlineBlock({
456
+ parent: this,
457
+ block: part.value
458
+ });
459
+ }
460
+ else {
461
+ return new Text({
462
+ parent: this,
463
+ content: part.value
464
+ });
465
+ }
466
+ });
467
+ this.yContent.insert(this.content.length, editableSuggestions.map((suggestion) => 'yBlock' in suggestion ? suggestion.yBlock : suggestion.yText));
468
+ this.suggestions = null;
469
+ this.normalizeContent();
470
+ }
471
+ export function deleteContentAtRange({ start, end }) {
472
+ const [startIndex, startOffset] = start;
473
+ const [endIndex, endOffset] = end;
474
+ let numberToDelete = 0;
475
+ this.content.slice(startIndex, endIndex + 1).forEach((part, index) => {
476
+ const isFirstPart = index === 0;
477
+ const isLastPart = index === endIndex - startIndex;
478
+ if (part instanceof Text) {
479
+ if (isFirstPart) {
480
+ // Delete from offset to end
481
+ part.yText.delete(startOffset, part.yText.length - startOffset);
482
+ }
483
+ else if (isLastPart) {
484
+ // Delete from start to offset
485
+ part.yText.delete(0, endOffset);
486
+ }
487
+ else {
488
+ numberToDelete++;
489
+ // Delete entire text element
490
+ }
491
+ }
492
+ else {
493
+ // For inline blocks, always delete the entire element
494
+ numberToDelete++;
495
+ }
496
+ });
497
+ this.yContent.delete(startIndex + 1, numberToDelete);
498
+ this.normalizeContent();
499
+ }
@@ -0,0 +1,14 @@
1
+ import type { YBlock } from '../utils/json.js';
2
+ import type { Block } from './block.svelte.js';
3
+ import { InlineBlock } from './inlineBlock.svelte.js';
4
+ import { Text } from '../text/text.svelte.js';
5
+ import * as Y from 'yjs';
6
+ export declare class Content {
7
+ parent: Block;
8
+ content: (Text | InlineBlock)[];
9
+ constructor({ parent, content }: {
10
+ parent: Block;
11
+ content: (Text | InlineBlock)[];
12
+ });
13
+ }
14
+ export declare function observeContent(this: Content, event: Y.YArrayEvent<YBlock | Y.Text>): void;
@@ -0,0 +1,40 @@
1
+ import { InlineBlock } from './inlineBlock.svelte.js';
2
+ import { Text } from '../text/text.svelte.js';
3
+ import * as Y from 'yjs';
4
+ import { batch, normalizeContent } from './block.utils.js';
5
+ export class Content {
6
+ parent;
7
+ content;
8
+ constructor({ parent, content }) {
9
+ this.parent = parent;
10
+ this.content = content;
11
+ }
12
+ }
13
+ export function observeContent(event) {
14
+ let start = 0;
15
+ event.delta.forEach(({ retain, delete: _delete, insert }) => {
16
+ if (retain) {
17
+ start += retain;
18
+ }
19
+ if (_delete) {
20
+ this.content.splice(start, _delete);
21
+ }
22
+ if (Array.isArray(insert)) {
23
+ for (let i = 0; i < insert.length; i++) {
24
+ const yElement = insert[i];
25
+ if (yElement instanceof Y.Text) {
26
+ const text = new Text({ parent: this.parent, yText: yElement });
27
+ this.content.splice(start, 0, text);
28
+ }
29
+ else {
30
+ const inlineBlock = new InlineBlock({ parent: this.parent, yBlock: yElement });
31
+ this.content.splice(start, 0, inlineBlock);
32
+ }
33
+ start += 1;
34
+ }
35
+ }
36
+ });
37
+ this.content.forEach((part, index) => {
38
+ part.index = index;
39
+ });
40
+ }
@@ -0,0 +1,30 @@
1
+ import type { Edytor } from '../edytor.svelte.js';
2
+ import type { InlineBlockDefinition } from '../plugins.js';
3
+ import type { JSONInlineBlock, YBlock } from '../utils/json.js';
4
+ import type { Block } from './block.svelte.js';
5
+ export declare class InlineBlock {
6
+ #private;
7
+ _def: "inline";
8
+ readonly: boolean;
9
+ parent: Block;
10
+ data: any;
11
+ id: string;
12
+ yBlock: YBlock;
13
+ index: number;
14
+ definition: InlineBlockDefinition;
15
+ edytor: Edytor;
16
+ node: HTMLElement | undefined;
17
+ get type(): string;
18
+ set type(value: string);
19
+ get value(): JSONInlineBlock;
20
+ constructor({ parent, block, yBlock }: {
21
+ parent: Block;
22
+ } & ({
23
+ yBlock?: undefined;
24
+ block: JSONInlineBlock;
25
+ } | {
26
+ yBlock: YBlock;
27
+ block?: undefined;
28
+ }));
29
+ attach: (node: HTMLElement) => void;
30
+ }
@@ -0,0 +1,53 @@
1
+ import * as Y from 'yjs';
2
+ import { id } from '../utils.js';
3
+ export class InlineBlock {
4
+ _def = 'inline';
5
+ readonly = false;
6
+ parent;
7
+ data = $state({});
8
+ id;
9
+ yBlock;
10
+ #type = $state('inline');
11
+ index = $state(0);
12
+ definition = $state({});
13
+ edytor;
14
+ node;
15
+ get type() {
16
+ return this.#type;
17
+ }
18
+ set type(value) {
19
+ this.#type = value;
20
+ this.yBlock.set('type', value);
21
+ }
22
+ get value() {
23
+ return {
24
+ id: this.id,
25
+ type: this.#type,
26
+ data: this.data
27
+ };
28
+ }
29
+ constructor({ parent, block, yBlock }) {
30
+ this.parent = parent;
31
+ this.edytor = parent.edytor;
32
+ this.id = (yBlock?.doc && yBlock?.get('id')) || id('i');
33
+ if (block !== undefined) {
34
+ this.#type = block.type;
35
+ this.data = block.data || {};
36
+ this.yBlock = new Y.Map(Object.entries({
37
+ type: this.#type
38
+ }));
39
+ }
40
+ else {
41
+ this.yBlock = yBlock;
42
+ this.#type = yBlock.get('type');
43
+ this.data = {};
44
+ }
45
+ this.definition = this.edytor.getBlockDefinition('inline', this.#type);
46
+ }
47
+ attach = (node) => {
48
+ node.contentEditable = 'false';
49
+ node.dataset.edytorInlineBlock = this.#type;
50
+ this.edytor.idToInlineBlock.set(this.id, this);
51
+ this.node = node;
52
+ };
53
+ }
@@ -0,0 +1,27 @@
1
+ <script lang="ts">
2
+ import { Block } from '../block/block.svelte.js';
3
+ import Child from './Block.svelte';
4
+ import Content from './Content.svelte';
5
+
6
+ let {
7
+ block
8
+ }: {
9
+ block: Block;
10
+ } = $props();
11
+
12
+ const snippet = $derived(block.definition.snippet);
13
+ </script>
14
+
15
+ {#snippet content()}
16
+ <Content {block} />
17
+ {/snippet}
18
+
19
+ {#snippet children()}
20
+ {#each block.children as child (child.id)}
21
+ <Child block={child} />
22
+ {/each}
23
+ {/snippet}
24
+
25
+ {#if snippet}
26
+ {@render snippet({ block, content, children: block.children.length ? children : null })}
27
+ {/if}
@@ -0,0 +1,7 @@
1
+ import { Block } from '../block/block.svelte.js';
2
+ type $$ComponentProps = {
3
+ block: Block;
4
+ };
5
+ declare const Block: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type Block = ReturnType<typeof Block>;
7
+ export default Block;