@blocknote/core 0.47.0 → 0.47.2

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 (77) hide show
  1. package/dist/BlockNoteExtension-BWw0r8Gy.cjs.map +1 -1
  2. package/dist/BlockNoteExtension-C2X7LW-V.js.map +1 -1
  3. package/dist/{BlockNoteSchema-DT4bdXj5.cjs → BlockNoteSchema-CCs_V3lo.cjs} +2 -2
  4. package/dist/{BlockNoteSchema-DT4bdXj5.cjs.map → BlockNoteSchema-CCs_V3lo.cjs.map} +1 -1
  5. package/dist/{BlockNoteSchema-1r-ln0Q0.js → BlockNoteSchema-ooiKsd5B.js} +2 -2
  6. package/dist/{BlockNoteSchema-1r-ln0Q0.js.map → BlockNoteSchema-ooiKsd5B.js.map} +1 -1
  7. package/dist/{TrailingNode-DZag-Nvu.js → TrailingNode-GzE59m_7.js} +588 -416
  8. package/dist/TrailingNode-GzE59m_7.js.map +1 -0
  9. package/dist/TrailingNode-n0WdMPUl.cjs +2 -0
  10. package/dist/TrailingNode-n0WdMPUl.cjs.map +1 -0
  11. package/dist/blocknote.cjs +4 -4
  12. package/dist/blocknote.cjs.map +1 -1
  13. package/dist/blocknote.js +1206 -955
  14. package/dist/blocknote.js.map +1 -1
  15. package/dist/blocks.cjs +1 -1
  16. package/dist/blocks.js +2 -2
  17. package/dist/comments.cjs.map +1 -1
  18. package/dist/comments.js.map +1 -1
  19. package/dist/defaultBlocks-Dg9kQWXm.cjs +6 -0
  20. package/dist/defaultBlocks-Dg9kQWXm.cjs.map +1 -0
  21. package/dist/{defaultBlocks-BSOEW3GR.js → defaultBlocks-ZzGbYgQn.js} +627 -543
  22. package/dist/defaultBlocks-ZzGbYgQn.js.map +1 -0
  23. package/dist/extensions.cjs +1 -1
  24. package/dist/extensions.cjs.map +1 -1
  25. package/dist/extensions.js +33 -54
  26. package/dist/extensions.js.map +1 -1
  27. package/dist/locales.cjs +1 -1
  28. package/dist/locales.cjs.map +1 -1
  29. package/dist/locales.js +25 -24
  30. package/dist/locales.js.map +1 -1
  31. package/dist/style.css +1 -1
  32. package/dist/tsconfig.tsbuildinfo +1 -1
  33. package/dist/webpack-stats.json +1 -1
  34. package/package.json +1 -10
  35. package/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts +33 -7
  36. package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +7 -1
  37. package/src/blocks/Heading/block.ts +48 -1
  38. package/src/blocks/ListItem/ToggleListItem/block.ts +51 -1
  39. package/src/blocks/Paragraph/block.ts +1 -1
  40. package/src/blocks/getDetailsContent.ts +77 -0
  41. package/src/comments/threadstore/TipTapThreadStore.ts +5 -5
  42. package/src/comments/threadstore/tiptap/types.ts +131 -0
  43. package/src/editor/Block.css +6 -0
  44. package/src/editor/BlockNoteEditor.ts +9 -14
  45. package/src/editor/managers/ExtensionManager/symbol.ts +0 -1
  46. package/src/editor/managers/SelectionManager.ts +3 -1
  47. package/src/extensions/Collaboration/YCursorPlugin.ts +3 -1
  48. package/src/extensions/DropCursor/DropCursor.ts +262 -25
  49. package/src/extensions/DropCursor/utils.ts +195 -0
  50. package/src/extensions/SuggestionMenu/SuggestionMenu.test.ts +191 -0
  51. package/src/extensions/SuggestionMenu/SuggestionMenu.ts +28 -11
  52. package/src/extensions/tiptap-extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +438 -53
  53. package/src/i18n/locales/fa.ts +4 -21
  54. package/src/i18n/locales/index.ts +1 -1
  55. package/src/i18n/locales/ru.ts +1 -1
  56. package/src/i18n/locales/uz.ts +22 -4
  57. package/src/index.ts +1 -0
  58. package/src/schema/blocks/createSpec.ts +35 -45
  59. package/src/schema/blocks/types.ts +101 -1
  60. package/types/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.d.ts +5 -0
  61. package/types/src/blocks/getDetailsContent.d.ts +19 -0
  62. package/types/src/comments/threadstore/TipTapThreadStore.d.ts +1 -1
  63. package/types/src/comments/threadstore/tiptap/types.d.ts +73 -0
  64. package/types/src/editor/BlockNoteEditor.d.ts +6 -9
  65. package/types/src/extensions/DropCursor/DropCursor.d.ts +42 -5
  66. package/types/src/extensions/DropCursor/utils.d.ts +48 -0
  67. package/types/src/extensions/SuggestionMenu/SuggestionMenu.d.ts +12 -3
  68. package/types/src/extensions/SuggestionMenu/SuggestionMenu.test.d.ts +1 -0
  69. package/types/src/index.d.ts +1 -0
  70. package/types/src/schema/blocks/createSpec.d.ts +3 -3
  71. package/types/src/schema/blocks/types.d.ts +31 -1
  72. package/dist/TrailingNode-DZag-Nvu.js.map +0 -1
  73. package/dist/TrailingNode-tesI8f7N.cjs +0 -2
  74. package/dist/TrailingNode-tesI8f7N.cjs.map +0 -1
  75. package/dist/defaultBlocks-BSOEW3GR.js.map +0 -1
  76. package/dist/defaultBlocks-D049Pbme.cjs +0 -6
  77. package/dist/defaultBlocks-D049Pbme.cjs.map +0 -1
@@ -1,8 +1,11 @@
1
1
  import { Extension } from "@tiptap/core";
2
-
2
+ import { Fragment, Node } from "prosemirror-model";
3
3
  import { TextSelection } from "prosemirror-state";
4
+
4
5
  import {
5
6
  getBottomNestedBlockInfo,
7
+ getNextBlockInfo,
8
+ getParentBlockInfo,
6
9
  getPrevBlockInfo,
7
10
  mergeBlocksCommand,
8
11
  } from "../../../api/blockManipulation/commands/mergeBlocks/mergeBlocks.js";
@@ -10,7 +13,10 @@ import { nestBlock } from "../../../api/blockManipulation/commands/nestBlock/nes
10
13
  import { fixColumnList } from "../../../api/blockManipulation/commands/replaceBlocks/util/fixColumnList.js";
11
14
  import { splitBlockCommand } from "../../../api/blockManipulation/commands/splitBlock/splitBlock.js";
12
15
  import { updateBlockCommand } from "../../../api/blockManipulation/commands/updateBlock/updateBlock.js";
13
- import { getBlockInfoFromSelection } from "../../../api/getBlockInfoFromPos.js";
16
+ import {
17
+ getBlockInfoFromResolvedPos,
18
+ getBlockInfoFromSelection,
19
+ } from "../../../api/getBlockInfoFromPos.js";
14
20
  import { BlockNoteEditor } from "../../../editor/BlockNoteEditor.js";
15
21
  import { FormattingToolbarExtension } from "../../FormattingToolbar/FormattingToolbar.js";
16
22
  import { FilePanelExtension } from "../../FilePanel/FilePanel.js";
@@ -83,6 +89,21 @@ export const KeyboardShortcutsExtension = Extension.create<{
83
89
  }
84
90
  const { bnBlock: blockContainer, blockContent } = blockInfo;
85
91
 
92
+ const prevBlockInfo = getPrevBlockInfo(
93
+ state.doc,
94
+ blockInfo.bnBlock.beforePos,
95
+ );
96
+ // If the previous block has no inline content, it can't be merged.
97
+ // It's instead deleted, which is done later in the chan, so we
98
+ // return early here.
99
+ if (
100
+ !prevBlockInfo ||
101
+ !prevBlockInfo.isBlockContainer ||
102
+ prevBlockInfo.blockContent.node.type.spec.content !== "inline*"
103
+ ) {
104
+ return false;
105
+ }
106
+
86
107
  const selectionAtBlockStart =
87
108
  state.selection.from === blockContent.beforePos + 1;
88
109
  const selectionEmpty = state.selection.empty;
@@ -98,9 +119,46 @@ export const KeyboardShortcutsExtension = Extension.create<{
98
119
 
99
120
  return false;
100
121
  }),
122
+ // If the previous block is a columnList, moves the current block to
123
+ // the end of the last column in it.
124
+ () =>
125
+ commands.command(({ state, tr, dispatch }) => {
126
+ const blockInfo = getBlockInfoFromSelection(state);
127
+ if (!blockInfo.isBlockContainer) {
128
+ return false;
129
+ }
130
+
131
+ const prevBlockInfo = getPrevBlockInfo(
132
+ state.doc,
133
+ blockInfo.bnBlock.beforePos,
134
+ );
135
+ if (!prevBlockInfo || prevBlockInfo.isBlockContainer) {
136
+ return false;
137
+ }
138
+
139
+ if (dispatch) {
140
+ const columnAfterPos = prevBlockInfo.bnBlock.afterPos - 1;
141
+ const $blockAfterPos = tr.doc.resolve(columnAfterPos - 1);
142
+
143
+ tr.delete(
144
+ blockInfo.bnBlock.beforePos,
145
+ blockInfo.bnBlock.afterPos,
146
+ );
147
+ tr.insert($blockAfterPos.pos, blockInfo.bnBlock.node);
148
+ tr.setSelection(
149
+ TextSelection.near(tr.doc.resolve($blockAfterPos.pos + 1)),
150
+ );
151
+
152
+ return true;
153
+ }
154
+
155
+ return false;
156
+ }),
157
+ // If the block is the first in a column, moves it to the end of the
158
+ // previous column. If there is no previous column, moves it above the
159
+ // columnList.
101
160
  () =>
102
161
  commands.command(({ state, tr, dispatch }) => {
103
- // when at the start of a first block in a column
104
162
  const blockInfo = getBlockInfoFromSelection(state);
105
163
  if (!blockInfo.isBlockContainer) {
106
164
  return false;
@@ -116,7 +174,6 @@ export const KeyboardShortcutsExtension = Extension.create<{
116
174
 
117
175
  const prevBlock = $pos.nodeBefore;
118
176
  if (prevBlock) {
119
- // should be no previous block
120
177
  return false;
121
178
  }
122
179
 
@@ -130,31 +187,22 @@ export const KeyboardShortcutsExtension = Extension.create<{
130
187
  const columnListPos = $columnPos.before();
131
188
 
132
189
  if (dispatch) {
133
- const fragment = tr.doc.slice(
134
- blockInfo.bnBlock.beforePos,
135
- blockInfo.bnBlock.afterPos,
136
- ).content;
137
-
138
190
  tr.delete(
139
191
  blockInfo.bnBlock.beforePos,
140
192
  blockInfo.bnBlock.afterPos,
141
193
  );
194
+ fixColumnList(tr, columnListPos);
142
195
 
143
- if ($columnPos.index() === 0) {
144
- // Fix `columnList` and insert the block before it.
145
- fixColumnList(tr, columnListPos);
146
- tr.insert(columnListPos, fragment);
196
+ if ($columnPos.pos === columnListPos + 1) {
197
+ tr.insert(columnListPos, blockInfo.bnBlock.node);
147
198
  tr.setSelection(
148
199
  TextSelection.near(tr.doc.resolve(columnListPos)),
149
200
  );
150
201
  } else {
151
- // Insert the block at the end of the first column and fix
152
- // `columnList`.
153
- tr.insert($columnPos.pos - 1, fragment);
202
+ tr.insert($columnPos.pos - 1, blockInfo.bnBlock.node);
154
203
  tr.setSelection(
155
- TextSelection.near(tr.doc.resolve($columnPos.pos - 1)),
204
+ TextSelection.near(tr.doc.resolve($columnPos.pos)),
156
205
  );
157
- fixColumnList(tr, columnListPos);
158
206
  }
159
207
  }
160
208
 
@@ -208,12 +256,8 @@ export const KeyboardShortcutsExtension = Extension.create<{
208
256
  } else if (
209
257
  prevBlockInfo.blockContent.node.type.spec.content === ""
210
258
  ) {
211
- const nonEditableBlockContentStartPos =
212
- prevBlockInfo.blockContent.afterPos -
213
- prevBlockInfo.blockContent.node.nodeSize;
214
-
215
259
  chainedCommands = chainedCommands.setNodeSelection(
216
- nonEditableBlockContentStartPos,
260
+ prevBlockInfo.blockContent.beforePos,
217
261
  );
218
262
  } else {
219
263
  const blockContentStartPos =
@@ -242,8 +286,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
242
286
  const blockInfo = getBlockInfoFromSelection(state);
243
287
 
244
288
  if (!blockInfo.isBlockContainer) {
245
- // TODO
246
- throw new Error(`todo`);
289
+ return false;
247
290
  }
248
291
 
249
292
  const selectionAtBlockStart =
@@ -262,8 +305,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
262
305
  );
263
306
 
264
307
  if (!bottomBlock.isBlockContainer) {
265
- // TODO
266
- throw new Error(`todo`);
308
+ return false;
267
309
  }
268
310
 
269
311
  const prevBlockNotTableAndNoContent =
@@ -294,50 +336,393 @@ export const KeyboardShortcutsExtension = Extension.create<{
294
336
  ]);
295
337
 
296
338
  const handleDelete = () =>
297
- this.editor.commands.first(({ commands }) => [
339
+ this.editor.commands.first(({ chain, commands }) => [
298
340
  // Deletes the selection if it's not empty.
299
341
  () => commands.deleteSelection(),
342
+ // Deletes the first child block and un-nests its children, if the
343
+ // selection is empty and at the end of the current block. If both the
344
+ // parent and child blocks have inline content, the child block's
345
+ // content is appended to the parent's. The child block's own children
346
+ // are unindented before it's deleted.
347
+ () =>
348
+ commands.command(({ state }) => {
349
+ const blockInfo = getBlockInfoFromSelection(state);
350
+ if (!blockInfo.isBlockContainer || !blockInfo.childContainer) {
351
+ return false;
352
+ }
353
+ const { blockContent, childContainer } = blockInfo;
354
+
355
+ const selectionAtBlockEnd =
356
+ state.selection.from === blockContent.afterPos - 1;
357
+ const selectionEmpty = state.selection.empty;
358
+
359
+ const firstChildBlockInfo = getBlockInfoFromResolvedPos(
360
+ state.doc.resolve(childContainer.beforePos + 1),
361
+ );
362
+ if (!firstChildBlockInfo.isBlockContainer) {
363
+ return false;
364
+ }
365
+
366
+ if (selectionAtBlockEnd && selectionEmpty) {
367
+ const firstChildBlockContent =
368
+ firstChildBlockInfo.blockContent.node;
369
+ const firstChildBlockHasInlineContent =
370
+ firstChildBlockContent.type.spec.content === "inline*";
371
+ const blockHasInlineContent =
372
+ blockContent.node.type.spec.content === "inline*";
373
+
374
+ return (
375
+ chain()
376
+ // Un-nests child block's children if necessary.
377
+ .insertContentAt(
378
+ firstChildBlockInfo.bnBlock.afterPos,
379
+ firstChildBlockInfo.childContainer?.node.content ||
380
+ Fragment.empty,
381
+ )
382
+ .deleteRange(
383
+ // Deletes whole child container if there's only one child.
384
+ childContainer.node.childCount === 1
385
+ ? {
386
+ from: childContainer.beforePos,
387
+ to: childContainer.afterPos,
388
+ }
389
+ : {
390
+ from: firstChildBlockInfo.bnBlock.beforePos,
391
+ to: firstChildBlockInfo.bnBlock.afterPos,
392
+ },
393
+ )
394
+ // Appends inline content from child block if possible.
395
+ .insertContentAt(
396
+ state.selection.from,
397
+ firstChildBlockHasInlineContent && blockHasInlineContent
398
+ ? firstChildBlockContent.content
399
+ : null,
400
+ )
401
+ .setTextSelection(state.selection.from)
402
+ .scrollIntoView()
403
+ .run()
404
+ );
405
+ }
406
+
407
+ return false;
408
+ }),
300
409
  // Merges block with the next one (at the same nesting level or lower),
301
410
  // if one exists, the block has no children, and the selection is at the
302
411
  // end of the block.
303
412
  () =>
304
413
  commands.command(({ state }) => {
305
- // TODO: Change this to not rely on offsets & schema assumptions
306
414
  const blockInfo = getBlockInfoFromSelection(state);
307
415
  if (!blockInfo.isBlockContainer) {
308
416
  return false;
309
417
  }
310
- const {
311
- bnBlock: blockContainer,
312
- blockContent,
313
- childContainer,
314
- } = blockInfo;
418
+ const { bnBlock: blockContainer, blockContent } = blockInfo;
419
+
420
+ const nextBlockInfo = getNextBlockInfo(
421
+ state.doc,
422
+ blockInfo.bnBlock.beforePos,
423
+ );
424
+ if (!nextBlockInfo || !nextBlockInfo.isBlockContainer) {
425
+ return false;
426
+ }
315
427
 
316
- const { depth } = state.doc.resolve(blockContainer.beforePos);
317
- const blockAtDocEnd =
318
- blockContainer.afterPos === state.doc.nodeSize - 3;
319
428
  const selectionAtBlockEnd =
320
429
  state.selection.from === blockContent.afterPos - 1;
321
430
  const selectionEmpty = state.selection.empty;
322
- const hasChildBlocks = childContainer !== undefined;
323
431
 
324
- if (
325
- !blockAtDocEnd &&
326
- selectionAtBlockEnd &&
327
- selectionEmpty &&
328
- !hasChildBlocks
329
- ) {
330
- let oldDepth = depth;
331
- let newPos = blockContainer.afterPos + 1;
332
- let newDepth = state.doc.resolve(newPos).depth;
333
-
334
- while (newDepth < oldDepth) {
335
- oldDepth = newDepth;
336
- newPos += 2;
337
- newDepth = state.doc.resolve(newPos).depth;
432
+ const posBetweenBlocks = blockContainer.afterPos;
433
+
434
+ if (selectionAtBlockEnd && selectionEmpty) {
435
+ return chain()
436
+ .command(mergeBlocksCommand(posBetweenBlocks))
437
+ .scrollIntoView()
438
+ .run();
439
+ }
440
+
441
+ return false;
442
+ }),
443
+ // If the previous block is a columnList, moves the current block to
444
+ // the end of the last column in it.
445
+ () =>
446
+ commands.command(({ state, tr, dispatch }) => {
447
+ const blockInfo = getBlockInfoFromSelection(state);
448
+ if (!blockInfo.isBlockContainer) {
449
+ return false;
450
+ }
451
+
452
+ const nextBlockInfo = getNextBlockInfo(
453
+ state.doc,
454
+ blockInfo.bnBlock.beforePos,
455
+ );
456
+ if (!nextBlockInfo || nextBlockInfo.isBlockContainer) {
457
+ return false;
458
+ }
459
+
460
+ if (dispatch) {
461
+ const columnBeforePos = nextBlockInfo.bnBlock.beforePos + 1;
462
+ const $blockBeforePos = tr.doc.resolve(columnBeforePos + 1);
463
+
464
+ tr.delete(
465
+ $blockBeforePos.pos,
466
+ $blockBeforePos.pos + $blockBeforePos.nodeAfter!.nodeSize,
467
+ );
468
+ fixColumnList(tr, nextBlockInfo.bnBlock.beforePos);
469
+ tr.insert(blockInfo.bnBlock.afterPos, $blockBeforePos.nodeAfter!);
470
+ tr.setSelection(
471
+ TextSelection.near(tr.doc.resolve($blockBeforePos.pos)),
472
+ );
473
+
474
+ return true;
475
+ }
476
+
477
+ return false;
478
+ }),
479
+ // If the block is the last in a column, moves it to the start of the
480
+ // next column. If there is no next column, moves it below the
481
+ // columnList.
482
+ () =>
483
+ commands.command(({ state, tr, dispatch }) => {
484
+ const blockInfo = getBlockInfoFromSelection(state);
485
+ if (!blockInfo.isBlockContainer) {
486
+ return false;
487
+ }
488
+
489
+ const selectionAtBlockEnd =
490
+ tr.selection.from === blockInfo.blockContent.afterPos - 1;
491
+ if (!selectionAtBlockEnd) {
492
+ return false;
493
+ }
494
+
495
+ const $pos = tr.doc.resolve(blockInfo.bnBlock.afterPos);
496
+
497
+ const nextBlock = $pos.nodeAfter;
498
+ if (nextBlock) {
499
+ return false;
500
+ }
501
+
502
+ const parentBlock = $pos.node();
503
+ if (parentBlock.type.name !== "column") {
504
+ return false;
505
+ }
506
+
507
+ const $blockEndPos = tr.doc.resolve(blockInfo.bnBlock.afterPos);
508
+ const $columnEndPos = tr.doc.resolve($blockEndPos.after());
509
+ const columnListEndPos = $columnEndPos.after();
510
+
511
+ if (dispatch) {
512
+ // Position before first block in next column, or first block
513
+ // after columnList if there is no next column.
514
+ const nextBlockBeforePos =
515
+ $columnEndPos.pos === columnListEndPos - 1
516
+ ? columnListEndPos
517
+ : $columnEndPos.pos + 1;
518
+ const nextBlockInfo = getBlockInfoFromResolvedPos(
519
+ tr.doc.resolve(nextBlockBeforePos),
520
+ );
521
+
522
+ tr.delete(
523
+ nextBlockInfo.bnBlock.beforePos,
524
+ nextBlockInfo.bnBlock.afterPos,
525
+ );
526
+ fixColumnList(
527
+ tr,
528
+ columnListEndPos - $columnEndPos.node().nodeSize,
529
+ );
530
+ tr.insert($blockEndPos.pos, nextBlockInfo.bnBlock.node);
531
+ tr.setSelection(
532
+ TextSelection.near(tr.doc.resolve(nextBlockBeforePos)),
533
+ );
534
+ }
535
+
536
+ return true;
537
+ }),
538
+ // Deletes the next block at either the same or lower nesting level, if
539
+ // the selection is empty and at the end of the block. If both the
540
+ // current and next blocks have inline content, the next block's
541
+ // content is appended to the current block's. The next block's own
542
+ // children are unindented before it's deleted.
543
+ () =>
544
+ commands.command(({ state }) => {
545
+ const blockInfo = getBlockInfoFromSelection(state);
546
+ if (!blockInfo.isBlockContainer) {
547
+ return false;
548
+ }
549
+ const { blockContent } = blockInfo;
550
+
551
+ const selectionAtBlockEnd =
552
+ state.selection.from === blockContent.afterPos - 1;
553
+ const selectionEmpty = state.selection.empty;
554
+
555
+ if (selectionAtBlockEnd && selectionEmpty) {
556
+ const getNextBlockInfoAtAnyLevel = (
557
+ doc: Node,
558
+ beforePos: number,
559
+ ) => {
560
+ const nextBlockInfo = getNextBlockInfo(doc, beforePos);
561
+ if (nextBlockInfo) {
562
+ return nextBlockInfo;
563
+ }
564
+
565
+ const parentBlockInfo = getParentBlockInfo(doc, beforePos);
566
+ if (!parentBlockInfo) {
567
+ return undefined;
568
+ }
569
+
570
+ return getNextBlockInfoAtAnyLevel(
571
+ doc,
572
+ parentBlockInfo.bnBlock.beforePos,
573
+ );
574
+ };
575
+
576
+ const nextBlockInfo = getNextBlockInfoAtAnyLevel(
577
+ state.doc,
578
+ blockInfo.bnBlock.beforePos,
579
+ );
580
+ if (!nextBlockInfo || !nextBlockInfo.isBlockContainer) {
581
+ return false;
582
+ }
583
+
584
+ const nextBlockContent = nextBlockInfo.blockContent.node;
585
+ const nextBlockHasInlineContent =
586
+ nextBlockContent.type.spec.content === "inline*";
587
+ const blockHasInlineContent =
588
+ blockContent.node.type.spec.content === "inline*";
589
+
590
+ return (
591
+ chain()
592
+ // Un-nests next block's children if necessary.
593
+ .insertContentAt(
594
+ nextBlockInfo.bnBlock.afterPos,
595
+ nextBlockInfo.childContainer?.node.content ||
596
+ Fragment.empty,
597
+ )
598
+ .deleteRange({
599
+ from: nextBlockInfo.bnBlock.beforePos,
600
+ to: nextBlockInfo.bnBlock.afterPos,
601
+ })
602
+ // Appends inline content from child block if possible.
603
+ .insertContentAt(
604
+ state.selection.from,
605
+ nextBlockHasInlineContent && blockHasInlineContent
606
+ ? nextBlockContent.content
607
+ : null,
608
+ )
609
+ .setTextSelection(state.selection.from)
610
+ .scrollIntoView()
611
+ .run()
612
+ );
613
+ }
614
+
615
+ return false;
616
+ }),
617
+ // Deletes the current block if it's an empty block with inline content,
618
+ // and moves the selection to the next block.
619
+ () =>
620
+ commands.command(({ state }) => {
621
+ const blockInfo = getBlockInfoFromSelection(state);
622
+ if (!blockInfo.isBlockContainer) {
623
+ return false;
624
+ }
625
+
626
+ const blockEmpty =
627
+ blockInfo.blockContent.node.childCount === 0 &&
628
+ blockInfo.blockContent.node.type.spec.content === "inline*";
629
+
630
+ if (blockEmpty) {
631
+ const nextBlockInfo = getNextBlockInfo(
632
+ state.doc,
633
+ blockInfo.bnBlock.beforePos,
634
+ );
635
+ if (!nextBlockInfo || !nextBlockInfo.isBlockContainer) {
636
+ return false;
637
+ }
638
+
639
+ let chainedCommands = chain();
640
+
641
+ if (
642
+ nextBlockInfo.blockContent.node.type.spec.content ===
643
+ "tableRow+"
644
+ ) {
645
+ const tableBlockStartPos = blockInfo.bnBlock.afterPos + 1;
646
+ const tableBlockContentStartPos = tableBlockStartPos + 1;
647
+ const firstRowStartPos = tableBlockContentStartPos + 1;
648
+ const firstCellStartPos = firstRowStartPos + 1;
649
+ const firstCellParagraphStartPos = firstCellStartPos + 1;
650
+
651
+ chainedCommands = chainedCommands.setTextSelection(
652
+ firstCellParagraphStartPos,
653
+ );
654
+ } else if (
655
+ nextBlockInfo.blockContent.node.type.spec.content === ""
656
+ ) {
657
+ chainedCommands = chainedCommands.setNodeSelection(
658
+ nextBlockInfo.blockContent.beforePos,
659
+ );
660
+ } else {
661
+ chainedCommands = chainedCommands.setTextSelection(
662
+ nextBlockInfo.blockContent.beforePos + 1,
663
+ );
338
664
  }
339
665
 
340
- return commands.command(mergeBlocksCommand(newPos - 1));
666
+ return chainedCommands
667
+ .deleteRange({
668
+ from: blockInfo.bnBlock.beforePos,
669
+ to: blockInfo.bnBlock.afterPos,
670
+ })
671
+ .scrollIntoView()
672
+ .run();
673
+ }
674
+
675
+ return false;
676
+ }),
677
+ // Deletes next block if it contains no content and isn't a table,
678
+ // when the selection is empty and at the end of the block. Moves the
679
+ // current block into the deleted block's place.
680
+ () =>
681
+ commands.command(({ state }) => {
682
+ const blockInfo = getBlockInfoFromSelection(state);
683
+
684
+ if (!blockInfo.isBlockContainer) {
685
+ return false;
686
+ }
687
+
688
+ const selectionAtBlockEnd =
689
+ state.selection.from === blockInfo.blockContent.afterPos - 1;
690
+ const selectionEmpty = state.selection.empty;
691
+
692
+ const nextBlockInfo = getNextBlockInfo(
693
+ state.doc,
694
+ blockInfo.bnBlock.beforePos,
695
+ );
696
+ if (!nextBlockInfo) {
697
+ return false;
698
+ }
699
+ if (!nextBlockInfo.isBlockContainer) {
700
+ return false;
701
+ }
702
+
703
+ if (nextBlockInfo && selectionAtBlockEnd && selectionEmpty) {
704
+ const nextBlockNotTableAndNoContent =
705
+ nextBlockInfo.blockContent.node.type.spec.content === "" ||
706
+ (nextBlockInfo.blockContent.node.type.spec.content ===
707
+ "inline*" &&
708
+ nextBlockInfo.blockContent.node.childCount === 0);
709
+
710
+ if (nextBlockNotTableAndNoContent) {
711
+ const childBlocks =
712
+ nextBlockInfo.bnBlock.node.lastChild!.content;
713
+ return chain()
714
+ .deleteRange({
715
+ from: nextBlockInfo.bnBlock.beforePos,
716
+ to: nextBlockInfo.bnBlock.afterPos,
717
+ })
718
+ .insertContentAt(
719
+ blockInfo.bnBlock.afterPos,
720
+ nextBlockInfo.bnBlock.node.childCount === 2
721
+ ? childBlocks
722
+ : null,
723
+ )
724
+ .run();
725
+ }
341
726
  }
342
727
 
343
728
  return false;
@@ -81,7 +81,7 @@ export const fa = {
81
81
  check_list: {
82
82
  title: "بازینه",
83
83
  subtext: "فهرست با جعبه انتخاب",
84
- aliases: ["چک لیست", "لیست انجام کار", "لیست تیک دار","بازینه"],
84
+ aliases: ["چک لیست", "لیست انجام کار", "لیست تیک دار", "بازینه"],
85
85
  group: "بلوک‌های پایه",
86
86
  },
87
87
  paragraph: {
@@ -111,36 +111,19 @@ export const fa = {
111
111
  image: {
112
112
  title: "تصویر",
113
113
  subtext: "تصویر با قابلیت تغییر اندازه و زیرنویس",
114
- aliases: [
115
- "تصویر",
116
- "عکس",
117
- "آپلود تصویر",
118
- "مدیا",
119
- "لینک عکس",
120
- ],
114
+ aliases: ["تصویر", "عکس", "آپلود تصویر", "مدیا", "لینک عکس"],
121
115
  group: "رسانه",
122
116
  },
123
117
  video: {
124
118
  title: "ویدیو",
125
119
  subtext: "ویدیو با قابلیت تغییر اندازه و زیرنویس",
126
- aliases: [
127
- "ویدیو",
128
- "فیلم",
129
- "آپلود ویدیو",
130
- "مدیا",
131
- ],
120
+ aliases: ["ویدیو", "فیلم", "آپلود ویدیو", "مدیا"],
132
121
  group: "رسانه",
133
122
  },
134
123
  audio: {
135
124
  title: "صوتی",
136
125
  subtext: "فایل صوتی جاسازی شده با زیرنویس",
137
- aliases: [
138
- "صوتی",
139
- "صدا",
140
- "آهنگ",
141
- "موسیقی",
142
- "آپلود صدا",
143
- ],
126
+ aliases: ["صوتی", "صدا", "آهنگ", "موسیقی", "آپلود صدا"],
144
127
  group: "رسانه",
145
128
  },
146
129
  file: {
@@ -20,4 +20,4 @@ export * from "./uk.js";
20
20
  export * from "./vi.js";
21
21
  export * from "./zh.js";
22
22
  export * from "./zh-tw.js";
23
- export * from "./uz.js";
23
+ export * from "./uz.js";
@@ -272,7 +272,7 @@ export const ru: Dictionary = {
272
272
  text_title: "Текст",
273
273
  background_title: "Задний фон",
274
274
  colors: {
275
- default: "По умолчинию",
275
+ default: "По умолчанию",
276
276
  gray: "Серый",
277
277
  brown: "Коричневый",
278
278
  red: "Красный",