@blocknote/core 0.37.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/blocknote.cjs +9 -9
  2. package/dist/blocknote.cjs.map +1 -1
  3. package/dist/blocknote.js +1298 -1326
  4. package/dist/blocknote.js.map +1 -1
  5. package/dist/{en-CvDoFvhc.js → en-Bq3Es3Np.js} +6 -12
  6. package/dist/en-Bq3Es3Np.js.map +1 -0
  7. package/dist/en-D3B48eJ7.cjs +2 -0
  8. package/dist/en-D3B48eJ7.cjs.map +1 -0
  9. package/dist/locales.cjs +1 -1
  10. package/dist/locales.cjs.map +1 -1
  11. package/dist/locales.js +109 -229
  12. package/dist/locales.js.map +1 -1
  13. package/dist/tsconfig.tsbuildinfo +1 -0
  14. package/dist/webpack-stats.json +1 -1
  15. package/package.json +7 -7
  16. package/src/api/clipboard/toClipboard/copyExtension.ts +0 -2
  17. package/src/api/exporters/html/externalHTMLExporter.ts +0 -1
  18. package/src/api/exporters/markdown/markdownExporter.ts +13 -22
  19. package/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts +2 -12
  20. package/src/api/parsers/html/parseHTML.ts +3 -2
  21. package/src/api/parsers/html/util/nestedLists.test.ts +8 -8
  22. package/src/api/parsers/markdown/parseMarkdown.ts +17 -14
  23. package/src/api/positionMapping.test.ts +155 -34
  24. package/src/api/positionMapping.ts +2 -2
  25. package/src/blocks/AudioBlockContent/AudioBlockContent.ts +0 -1
  26. package/src/blocks/FileBlockContent/helpers/render/createAddFileButton.ts +3 -2
  27. package/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.ts +1 -7
  28. package/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts +42 -17
  29. package/src/blocks/ImageBlockContent/ImageBlockContent.ts +0 -1
  30. package/src/blocks/VideoBlockContent/VideoBlockContent.ts +0 -1
  31. package/src/editor/BlockNoteEditor.ts +17 -23
  32. package/src/editor/BlockNoteExtensions.ts +3 -0
  33. package/src/extensions/Comments/CommentsPlugin.ts +2 -0
  34. package/src/extensions/SideMenu/SideMenuPlugin.ts +0 -2
  35. package/src/i18n/locales/ar.ts +6 -12
  36. package/src/i18n/locales/de.ts +6 -12
  37. package/src/i18n/locales/en.ts +6 -12
  38. package/src/i18n/locales/es.ts +6 -12
  39. package/src/i18n/locales/fr.ts +6 -12
  40. package/src/i18n/locales/he.ts +6 -12
  41. package/src/i18n/locales/hr.ts +6 -12
  42. package/src/i18n/locales/is.ts +6 -12
  43. package/src/i18n/locales/it.ts +6 -12
  44. package/src/i18n/locales/ja.ts +6 -12
  45. package/src/i18n/locales/ko.ts +6 -12
  46. package/src/i18n/locales/nl.ts +6 -12
  47. package/src/i18n/locales/no.ts +6 -12
  48. package/src/i18n/locales/pl.ts +6 -12
  49. package/src/i18n/locales/pt.ts +6 -12
  50. package/src/i18n/locales/ru.ts +6 -12
  51. package/src/i18n/locales/sk.ts +6 -12
  52. package/src/i18n/locales/uk.ts +6 -12
  53. package/src/i18n/locales/vi.ts +6 -12
  54. package/src/i18n/locales/zh-tw.ts +6 -12
  55. package/src/i18n/locales/zh.ts +6 -12
  56. package/src/index.ts +0 -1
  57. package/types/src/api/exporters/markdown/markdownExporter.d.ts +1 -1
  58. package/types/src/api/parsers/html/parseHTML.d.ts +1 -1
  59. package/types/src/api/parsers/markdown/parseMarkdown.d.ts +2 -2
  60. package/types/src/blocks/FileBlockContent/helpers/render/createAddFileButton.d.ts +1 -1
  61. package/types/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.d.ts +1 -1
  62. package/types/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.d.ts +1 -1
  63. package/types/src/editor/BlockNoteEditor.d.ts +6 -9
  64. package/types/src/editor/BlockNoteExtensions.d.ts +2 -0
  65. package/types/src/extensions/Comments/CommentsPlugin.d.ts +3 -1
  66. package/types/src/i18n/locales/en.d.ts +1 -12
  67. package/types/src/i18n/locales/sk.d.ts +1 -12
  68. package/types/src/index.d.ts +0 -1
  69. package/dist/en-CvDoFvhc.js.map +0 -1
  70. package/dist/en-ub2yVBX0.cjs +0 -2
  71. package/dist/en-ub2yVBX0.cjs.map +0 -1
  72. package/src/util/esmDependencies.ts +0 -51
  73. package/types/src/util/esmDependencies.d.ts +0 -24
@@ -1,23 +1,14 @@
1
- import { beforeEach, afterEach, describe, expect, it, vi } from "vitest";
1
+ import { describe, expect, it, vi } from "vitest";
2
2
  import * as Y from "yjs";
3
3
  import { BlockNoteEditor } from "../editor/BlockNoteEditor.js";
4
4
  import { trackPosition } from "./positionMapping.js";
5
5
 
6
6
  describe("PositionStorage with local editor", () => {
7
- let editor: BlockNoteEditor;
8
-
9
- beforeEach(() => {
10
- editor = BlockNoteEditor.create();
11
- editor.mount(document.createElement("div"));
12
- });
13
-
14
- afterEach(() => {
15
- editor.mount(undefined);
16
- editor._tiptapEditor.destroy();
17
- });
18
-
19
7
  describe("mount and unmount", () => {
20
8
  it("should register transaction handler on creation", () => {
9
+ const editor = BlockNoteEditor.create();
10
+ editor.mount(document.createElement("div"));
11
+
21
12
  editor._tiptapEditor.on = vi.fn();
22
13
  trackPosition(editor, 0);
23
14
 
@@ -25,24 +16,42 @@ describe("PositionStorage with local editor", () => {
25
16
  "transaction",
26
17
  expect.any(Function),
27
18
  );
19
+
20
+ editor.mount(undefined);
21
+ editor._tiptapEditor.destroy();
28
22
  });
29
23
  });
30
24
 
31
25
  describe("set and get positions", () => {
32
26
  it("should store and retrieve positions without Y.js", () => {
27
+ const editor = BlockNoteEditor.create();
28
+ editor.mount(document.createElement("div"));
29
+
33
30
  const getPos = trackPosition(editor, 10);
34
31
 
35
32
  expect(getPos()).toBe(10);
33
+
34
+ editor.mount(undefined);
35
+ editor._tiptapEditor.destroy();
36
36
  });
37
37
 
38
38
  it("should handle right side positions", () => {
39
+ const editor = BlockNoteEditor.create();
40
+ editor.mount(document.createElement("div"));
41
+
39
42
  const getPos = trackPosition(editor, 10, "right");
40
43
 
41
44
  expect(getPos()).toBe(10);
45
+
46
+ editor.mount(undefined);
47
+ editor._tiptapEditor.destroy();
42
48
  });
43
49
  });
44
50
 
45
51
  it("should update mapping for local transactions before the position", () => {
52
+ const editor = BlockNoteEditor.create();
53
+ editor.mount(document.createElement("div"));
54
+
46
55
  // Set initial content
47
56
  editor.insertBlocks(
48
57
  [
@@ -79,9 +88,15 @@ describe("PositionStorage with local editor", () => {
79
88
 
80
89
  // Position should be updated according to mapping
81
90
  expect(getPos()).toBe(14);
91
+
92
+ editor.mount(undefined);
93
+ editor._tiptapEditor.destroy();
82
94
  });
83
95
 
84
96
  it("should not update mapping for local transactions after the position", () => {
97
+ const editor = BlockNoteEditor.create();
98
+ editor.mount(document.createElement("div"));
99
+
85
100
  // Set initial content
86
101
  editor.insertBlocks(
87
102
  [
@@ -117,9 +132,15 @@ describe("PositionStorage with local editor", () => {
117
132
 
118
133
  // Position should not be updated
119
134
  expect(getPos()).toBe(10);
135
+
136
+ editor.mount(undefined);
137
+ editor._tiptapEditor.destroy();
120
138
  });
121
139
 
122
140
  it("should track positions on each side", () => {
141
+ const editor = BlockNoteEditor.create();
142
+ editor.mount(document.createElement("div"));
143
+
123
144
  editor.replaceBlocks(editor.document, [
124
145
  {
125
146
  type: "paragraph",
@@ -142,9 +163,15 @@ describe("PositionStorage with local editor", () => {
142
163
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
143
164
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
144
165
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
166
+
167
+ editor.mount(undefined);
168
+ editor._tiptapEditor.destroy();
145
169
  });
146
170
 
147
171
  it("should handle multiple transactions", () => {
172
+ const editor = BlockNoteEditor.create();
173
+ editor.mount(document.createElement("div"));
174
+
148
175
  editor.replaceBlocks(editor.document, [
149
176
  {
150
177
  type: "paragraph",
@@ -172,6 +199,9 @@ describe("PositionStorage with local editor", () => {
172
199
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
173
200
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
174
201
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
202
+
203
+ editor.mount(undefined);
204
+ editor._tiptapEditor.destroy();
175
205
  });
176
206
  });
177
207
 
@@ -202,16 +232,12 @@ describe("PositionStorage with remote editor", () => {
202
232
  }
203
233
 
204
234
  describe("remote editor", () => {
205
- let localEditor: BlockNoteEditor;
206
- let remoteEditor: BlockNoteEditor;
207
- let ydoc: Y.Doc;
208
- let remoteYdoc: Y.Doc;
209
-
210
- beforeEach(() => {
211
- ydoc = new Y.Doc();
212
- remoteYdoc = new Y.Doc();
235
+ it("should update the local position when collaborating", () => {
236
+ const ydoc = new Y.Doc();
237
+ const remoteYdoc = new Y.Doc();
238
+
213
239
  // Create a mock editor
214
- localEditor = BlockNoteEditor.create({
240
+ const localEditor = BlockNoteEditor.create({
215
241
  collaboration: {
216
242
  fragment: ydoc.getXmlFragment("doc"),
217
243
  user: { color: "#ff0000", name: "Local User" },
@@ -221,7 +247,7 @@ describe("PositionStorage with remote editor", () => {
221
247
  const div = document.createElement("div");
222
248
  localEditor.mount(div);
223
249
 
224
- remoteEditor = BlockNoteEditor.create({
250
+ const remoteEditor = BlockNoteEditor.create({
225
251
  collaboration: {
226
252
  fragment: remoteYdoc.getXmlFragment("doc"),
227
253
  user: { color: "#ff0000", name: "Remote User" },
@@ -232,18 +258,7 @@ describe("PositionStorage with remote editor", () => {
232
258
  const remoteDiv = document.createElement("div");
233
259
  remoteEditor.mount(remoteDiv);
234
260
  setupTwoWaySync(ydoc, remoteYdoc);
235
- });
236
-
237
- afterEach(() => {
238
- ydoc.destroy();
239
- remoteYdoc.destroy();
240
- localEditor.mount(undefined);
241
- localEditor._tiptapEditor.destroy();
242
- remoteEditor.mount(undefined);
243
- remoteEditor._tiptapEditor.destroy();
244
- });
245
261
 
246
- it("should update the local position when collaborating", () => {
247
262
  localEditor.replaceBlocks(localEditor.document, [
248
263
  {
249
264
  type: "paragraph",
@@ -271,9 +286,42 @@ describe("PositionStorage with remote editor", () => {
271
286
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
272
287
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
273
288
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
289
+
290
+ ydoc.destroy();
291
+ remoteYdoc.destroy();
292
+ localEditor.mount(undefined);
293
+ localEditor._tiptapEditor.destroy();
294
+ remoteEditor.mount(undefined);
295
+ remoteEditor._tiptapEditor.destroy();
274
296
  });
275
297
 
276
298
  it("should handle multiple transactions when collaborating", () => {
299
+ const ydoc = new Y.Doc();
300
+ const remoteYdoc = new Y.Doc();
301
+
302
+ // Create a mock editor
303
+ const localEditor = BlockNoteEditor.create({
304
+ collaboration: {
305
+ fragment: ydoc.getXmlFragment("doc"),
306
+ user: { color: "#ff0000", name: "Local User" },
307
+ provider: undefined,
308
+ },
309
+ });
310
+ const div = document.createElement("div");
311
+ localEditor.mount(div);
312
+
313
+ const remoteEditor = BlockNoteEditor.create({
314
+ collaboration: {
315
+ fragment: remoteYdoc.getXmlFragment("doc"),
316
+ user: { color: "#ff0000", name: "Remote User" },
317
+ provider: undefined,
318
+ },
319
+ });
320
+
321
+ const remoteDiv = document.createElement("div");
322
+ remoteEditor.mount(remoteDiv);
323
+ setupTwoWaySync(ydoc, remoteYdoc);
324
+
277
325
  localEditor.replaceBlocks(localEditor.document, [
278
326
  {
279
327
  type: "paragraph",
@@ -305,9 +353,42 @@ describe("PositionStorage with remote editor", () => {
305
353
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
306
354
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
307
355
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
356
+
357
+ ydoc.destroy();
358
+ remoteYdoc.destroy();
359
+ localEditor.mount(undefined);
360
+ localEditor._tiptapEditor.destroy();
361
+ remoteEditor.mount(undefined);
362
+ remoteEditor._tiptapEditor.destroy();
308
363
  });
309
364
 
310
365
  it("should update the local position from a remote transaction", () => {
366
+ const ydoc = new Y.Doc();
367
+ const remoteYdoc = new Y.Doc();
368
+
369
+ // Create a mock editor
370
+ const localEditor = BlockNoteEditor.create({
371
+ collaboration: {
372
+ fragment: ydoc.getXmlFragment("doc"),
373
+ user: { color: "#ff0000", name: "Local User" },
374
+ provider: undefined,
375
+ },
376
+ });
377
+ const div = document.createElement("div");
378
+ localEditor.mount(div);
379
+
380
+ const remoteEditor = BlockNoteEditor.create({
381
+ collaboration: {
382
+ fragment: remoteYdoc.getXmlFragment("doc"),
383
+ user: { color: "#ff0000", name: "Remote User" },
384
+ provider: undefined,
385
+ },
386
+ });
387
+
388
+ const remoteDiv = document.createElement("div");
389
+ remoteEditor.mount(remoteDiv);
390
+ setupTwoWaySync(ydoc, remoteYdoc);
391
+
311
392
  remoteEditor.replaceBlocks(remoteEditor.document, [
312
393
  {
313
394
  type: "paragraph",
@@ -335,9 +416,42 @@ describe("PositionStorage with remote editor", () => {
335
416
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
336
417
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
337
418
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
419
+
420
+ ydoc.destroy();
421
+ remoteYdoc.destroy();
422
+ localEditor.mount(undefined);
423
+ localEditor._tiptapEditor.destroy();
424
+ remoteEditor.mount(undefined);
425
+ remoteEditor._tiptapEditor.destroy();
338
426
  });
339
427
 
340
428
  it("should update the remote position from a remote transaction", () => {
429
+ const ydoc = new Y.Doc();
430
+ const remoteYdoc = new Y.Doc();
431
+
432
+ // Create a mock editor
433
+ const localEditor = BlockNoteEditor.create({
434
+ collaboration: {
435
+ fragment: ydoc.getXmlFragment("doc"),
436
+ user: { color: "#ff0000", name: "Local User" },
437
+ provider: undefined,
438
+ },
439
+ });
440
+ const div = document.createElement("div");
441
+ localEditor.mount(div);
442
+
443
+ const remoteEditor = BlockNoteEditor.create({
444
+ collaboration: {
445
+ fragment: remoteYdoc.getXmlFragment("doc"),
446
+ user: { color: "#ff0000", name: "Remote User" },
447
+ provider: undefined,
448
+ },
449
+ });
450
+
451
+ const remoteDiv = document.createElement("div");
452
+ remoteEditor.mount(remoteDiv);
453
+ setupTwoWaySync(ydoc, remoteYdoc);
454
+
341
455
  remoteEditor.replaceBlocks(remoteEditor.document, [
342
456
  {
343
457
  type: "paragraph",
@@ -365,6 +479,13 @@ describe("PositionStorage with remote editor", () => {
365
479
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
366
480
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
367
481
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
482
+
483
+ ydoc.destroy();
484
+ remoteYdoc.destroy();
485
+ localEditor.mount(undefined);
486
+ localEditor._tiptapEditor.destroy();
487
+ remoteEditor.mount(undefined);
488
+ remoteEditor._tiptapEditor.destroy();
368
489
  });
369
490
  });
370
491
  });
@@ -88,7 +88,7 @@ export function trackPosition(
88
88
 
89
89
  const relativePosition = absolutePositionToRelativePosition(
90
90
  // Track the position after the position if we are on the right side
91
- position + (side === "right" ? 1 : 0),
91
+ position + (side === "right" ? 1 : -1),
92
92
  ySyncPluginState.binding.type,
93
93
  ySyncPluginState.binding.mapping,
94
94
  );
@@ -109,6 +109,6 @@ export function trackPosition(
109
109
  throw new Error("Position not found, cannot track positions");
110
110
  }
111
111
 
112
- return pos + (side === "right" ? -1 : 0);
112
+ return pos + (side === "right" ? -1 : 1);
113
113
  };
114
114
  }
@@ -69,7 +69,6 @@ export const audioRender = (
69
69
  block,
70
70
  editor,
71
71
  { dom: audio },
72
- editor.dictionary.file_blocks.audio.add_button_text,
73
72
  icon.firstElementChild as HTMLElement,
74
73
  );
75
74
  };
@@ -4,7 +4,6 @@ import { BlockFromConfig, FileBlockConfig } from "../../../../schema/index.js";
4
4
  export const createAddFileButton = (
5
5
  block: BlockFromConfig<FileBlockConfig, any, any>,
6
6
  editor: BlockNoteEditor<any, any, any>,
7
- buttonText?: string,
8
7
  buttonIcon?: HTMLElement,
9
8
  ) => {
10
9
  const addFileButton = document.createElement("div");
@@ -23,7 +22,9 @@ export const createAddFileButton = (
23
22
  const addFileButtonText = document.createElement("p");
24
23
  addFileButtonText.className = "bn-add-file-button-text";
25
24
  addFileButtonText.innerHTML =
26
- buttonText || editor.dictionary.file_blocks.file.add_button_text;
25
+ block.type in editor.dictionary.file_blocks.add_button_text
26
+ ? editor.dictionary.file_blocks.add_button_text[block.type]
27
+ : editor.dictionary.file_blocks.add_button_text["file"];
27
28
  addFileButton.appendChild(addFileButtonText);
28
29
 
29
30
  // Prevents focus from moving to the button.
@@ -15,7 +15,6 @@ export const createFileBlockWrapper = (
15
15
  any
16
16
  >,
17
17
  element?: { dom: HTMLElement; destroy?: () => void },
18
- buttonText?: string,
19
18
  buttonIcon?: HTMLElement,
20
19
  ) => {
21
20
  const wrapper = document.createElement("div");
@@ -24,12 +23,7 @@ export const createFileBlockWrapper = (
24
23
  // Show the add file button if the file has not been uploaded yet. Change to
25
24
  // show a loader if a file upload for the block begins.
26
25
  if (block.props.url === "") {
27
- const addFileButton = createAddFileButton(
28
- block,
29
- editor,
30
- buttonText,
31
- buttonIcon,
32
- );
26
+ const addFileButton = createAddFileButton(block, editor, buttonIcon);
33
27
  wrapper.appendChild(addFileButton.dom);
34
28
 
35
29
  const destroyUploadStartHandler = editor.onUploadStart((blockId) => {
@@ -7,14 +7,12 @@ export const createResizableFileBlockWrapper = (
7
7
  editor: BlockNoteEditor<any, any, any>,
8
8
  element: { dom: HTMLElement; destroy?: () => void },
9
9
  resizeHandlesContainerElement: HTMLElement,
10
- buttonText: string,
11
- buttonIcon: HTMLElement,
10
+ buttonIcon?: HTMLElement,
12
11
  ): { dom: HTMLElement; destroy: () => void } => {
13
12
  const { dom, destroy } = createFileBlockWrapper(
14
13
  block,
15
14
  editor,
16
15
  element,
17
- buttonText,
18
16
  buttonIcon,
19
17
  );
20
18
  const wrapper = dom;
@@ -56,7 +54,7 @@ export const createResizableFileBlockWrapper = (
56
54
 
57
55
  // Updates the element width with an updated width depending on the cursor X
58
56
  // offset from when the resize began, and which resize handle is being used.
59
- const windowMouseMoveHandler = (event: MouseEvent) => {
57
+ const windowMouseMoveHandler = (event: MouseEvent | TouchEvent) => {
60
58
  if (!resizeParams) {
61
59
  if (
62
60
  !editor.isEditable &&
@@ -72,27 +70,26 @@ export const createResizableFileBlockWrapper = (
72
70
 
73
71
  let newWidth: number;
74
72
 
73
+ const clientX =
74
+ "touches" in event ? event.touches[0].clientX : event.clientX;
75
+
75
76
  if (block.props.textAlignment === "center") {
76
77
  if (resizeParams.handleUsed === "left") {
77
78
  newWidth =
78
79
  resizeParams.initialWidth +
79
- (resizeParams.initialClientX - event.clientX) * 2;
80
+ (resizeParams.initialClientX - clientX) * 2;
80
81
  } else {
81
82
  newWidth =
82
83
  resizeParams.initialWidth +
83
- (event.clientX - resizeParams.initialClientX) * 2;
84
+ (clientX - resizeParams.initialClientX) * 2;
84
85
  }
85
86
  } else {
86
87
  if (resizeParams.handleUsed === "left") {
87
88
  newWidth =
88
- resizeParams.initialWidth +
89
- resizeParams.initialClientX -
90
- event.clientX;
89
+ resizeParams.initialWidth + resizeParams.initialClientX - clientX;
91
90
  } else {
92
91
  newWidth =
93
- resizeParams.initialWidth +
94
- event.clientX -
95
- resizeParams.initialClientX;
92
+ resizeParams.initialWidth + clientX - resizeParams.initialClientX;
96
93
  }
97
94
  }
98
95
 
@@ -109,7 +106,7 @@ export const createResizableFileBlockWrapper = (
109
106
  };
110
107
  // Stops mouse movements from resizing the element and updates the block's
111
108
  // `width` prop to the new value.
112
- const windowMouseUpHandler = (event: MouseEvent) => {
109
+ const windowMouseUpHandler = (event: MouseEvent | TouchEvent) => {
113
110
  // Hides the drag handles if the cursor is no longer over the element.
114
111
  if (
115
112
  (!event.target ||
@@ -172,62 +169,90 @@ export const createResizableFileBlockWrapper = (
172
169
 
173
170
  // Sets the resize params, allowing the user to begin resizing the element by
174
171
  // moving the cursor left or right.
175
- const leftResizeHandleMouseDownHandler = (event: MouseEvent) => {
172
+ const leftResizeHandleMouseDownHandler = (event: MouseEvent | TouchEvent) => {
176
173
  event.preventDefault();
177
174
 
178
175
  if (!wrapper.contains(eventCaptureElement)) {
179
176
  wrapper.appendChild(eventCaptureElement);
180
177
  }
181
178
 
179
+ const clientX =
180
+ "touches" in event ? event.touches[0].clientX : event.clientX;
181
+
182
182
  resizeParams = {
183
183
  handleUsed: "left",
184
184
  initialWidth: wrapper.clientWidth,
185
- initialClientX: event.clientX,
185
+ initialClientX: clientX,
186
186
  };
187
187
  };
188
- const rightResizeHandleMouseDownHandler = (event: MouseEvent) => {
188
+ const rightResizeHandleMouseDownHandler = (
189
+ event: MouseEvent | TouchEvent,
190
+ ) => {
189
191
  event.preventDefault();
190
192
 
191
193
  if (!wrapper.contains(eventCaptureElement)) {
192
194
  wrapper.appendChild(eventCaptureElement);
193
195
  }
194
196
 
197
+ const clientX =
198
+ "touches" in event ? event.touches[0].clientX : event.clientX;
199
+
195
200
  resizeParams = {
196
201
  handleUsed: "right",
197
202
  initialWidth: wrapper.clientWidth,
198
- initialClientX: event.clientX,
203
+ initialClientX: clientX,
199
204
  };
200
205
  };
201
206
 
202
207
  window.addEventListener("mousemove", windowMouseMoveHandler);
208
+ window.addEventListener("touchmove", windowMouseMoveHandler);
203
209
  window.addEventListener("mouseup", windowMouseUpHandler);
210
+ window.addEventListener("touchend", windowMouseUpHandler);
204
211
  wrapper.addEventListener("mouseenter", wrapperMouseEnterHandler);
205
212
  wrapper.addEventListener("mouseleave", wrapperMouseLeaveHandler);
206
213
  leftResizeHandle.addEventListener(
207
214
  "mousedown",
208
215
  leftResizeHandleMouseDownHandler,
209
216
  );
217
+ leftResizeHandle.addEventListener(
218
+ "touchstart",
219
+ leftResizeHandleMouseDownHandler,
220
+ );
210
221
  rightResizeHandle.addEventListener(
211
222
  "mousedown",
212
223
  rightResizeHandleMouseDownHandler,
213
224
  );
225
+ rightResizeHandle.addEventListener(
226
+ "touchstart",
227
+ rightResizeHandleMouseDownHandler,
228
+ );
214
229
 
215
230
  return {
216
231
  dom: wrapper,
217
232
  destroy: () => {
218
233
  destroy?.();
219
234
  window.removeEventListener("mousemove", windowMouseMoveHandler);
235
+ window.removeEventListener("touchmove", windowMouseMoveHandler);
220
236
  window.removeEventListener("mouseup", windowMouseUpHandler);
237
+ window.removeEventListener("touchend", windowMouseUpHandler);
221
238
  wrapper.removeEventListener("mouseenter", wrapperMouseEnterHandler);
222
239
  wrapper.removeEventListener("mouseleave", wrapperMouseLeaveHandler);
223
240
  leftResizeHandle.removeEventListener(
224
241
  "mousedown",
225
242
  leftResizeHandleMouseDownHandler,
226
243
  );
244
+ leftResizeHandle.removeEventListener(
245
+ "touchstart",
246
+ leftResizeHandleMouseDownHandler,
247
+ );
227
248
  rightResizeHandle.removeEventListener(
228
249
  "mousedown",
229
250
  rightResizeHandleMouseDownHandler,
230
251
  );
252
+ rightResizeHandle.removeEventListener(
253
+ "touchstart",
254
+ rightResizeHandleMouseDownHandler,
255
+ );
231
256
  },
232
257
  };
233
258
  };
@@ -80,7 +80,6 @@ export const imageRender = (
80
80
  editor,
81
81
  { dom: imageWrapper },
82
82
  imageWrapper,
83
- editor.dictionary.file_blocks.image.add_button_text,
84
83
  icon.firstElementChild as HTMLElement,
85
84
  );
86
85
  };
@@ -80,7 +80,6 @@ export const videoRender = (
80
80
  editor,
81
81
  { dom: videoWrapper },
82
82
  videoWrapper,
83
- editor.dictionary.file_blocks.video.add_button_text,
84
83
  icon.firstElementChild as HTMLElement,
85
84
  );
86
85
  };
@@ -105,22 +105,21 @@ import { dropCursor } from "prosemirror-dropcursor";
105
105
  import { EditorView } from "prosemirror-view";
106
106
  import { redoCommand, undoCommand, ySyncPluginKey } from "y-prosemirror";
107
107
  import { createInternalHTMLSerializer } from "../api/exporters/html/internalHTMLSerializer.js";
108
- import { inlineContentToNodes } from "../api/nodeConversions/blockToNode.js";
109
- import { docToBlocks } from "../api/nodeConversions/nodeToBlock.js";
110
108
  import {
111
109
  BlocksChanged,
112
110
  getBlocksChangedByTransaction,
113
111
  } from "../api/getBlocksChangedByTransaction.js";
114
- import { nestedListsToBlockNoteStructure } from "../api/parsers/html/util/nestedLists.js";
112
+ import { inlineContentToNodes } from "../api/nodeConversions/blockToNode.js";
113
+ import { docToBlocks } from "../api/nodeConversions/nodeToBlock.js";
115
114
  import { CodeBlockOptions } from "../blocks/CodeBlockContent/CodeBlockContent.js";
116
115
  import type { ThreadStore, User } from "../comments/index.js";
116
+ import { BlockChangePlugin } from "../extensions/BlockChange/BlockChangePlugin.js";
117
117
  import type { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js";
118
118
  import type { ForkYDocPlugin } from "../extensions/Collaboration/ForkYDocPlugin.js";
119
119
  import { EventEmitter } from "../util/EventEmitter.js";
120
120
  import { BlockNoteExtension } from "./BlockNoteExtension.js";
121
121
 
122
122
  import "../style.css";
123
- import { BlockChangePlugin } from "../extensions/BlockChange/BlockChangePlugin.js";
124
123
 
125
124
  /**
126
125
  * A factory function that returns a BlockNoteExtension
@@ -201,6 +200,7 @@ export type BlockNoteEditorOptions<
201
200
  * @remarks `CommentsOptions`
202
201
  */
203
202
  comments?: {
203
+ schema?: BlockNoteSchema<any, any, any>;
204
204
  threadStore: ThreadStore;
205
205
  };
206
206
 
@@ -1574,9 +1574,9 @@ export class BlockNoteEditor<
1574
1574
  * @param blocks An array of blocks that should be serialized into HTML.
1575
1575
  * @returns The blocks, serialized as an HTML string.
1576
1576
  */
1577
- public async blocksToHTMLLossy(
1577
+ public blocksToHTMLLossy(
1578
1578
  blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,
1579
- ): Promise<string> {
1579
+ ): string {
1580
1580
  const exporter = createExternalHTMLExporter(this.pmSchema, this);
1581
1581
  return exporter.exportBlocks(blocks, {});
1582
1582
  }
@@ -1590,9 +1590,9 @@ export class BlockNoteEditor<
1590
1590
  * @param blocks An array of blocks that should be serialized into HTML.
1591
1591
  * @returns The blocks, serialized as an HTML string.
1592
1592
  */
1593
- public async blocksToFullHTML(
1593
+ public blocksToFullHTML(
1594
1594
  blocks: PartialBlock<BSchema, ISchema, SSchema>[],
1595
- ): Promise<string> {
1595
+ ): string {
1596
1596
  const exporter = createInternalHTMLSerializer(this.pmSchema, this);
1597
1597
  return exporter.serializeBlocks(blocks, {});
1598
1598
  }
@@ -1603,9 +1603,9 @@ export class BlockNoteEditor<
1603
1603
  * @param html The HTML string to parse blocks from.
1604
1604
  * @returns The blocks parsed from the HTML string.
1605
1605
  */
1606
- public async tryParseHTMLToBlocks(
1606
+ public tryParseHTMLToBlocks(
1607
1607
  html: string,
1608
- ): Promise<Block<BSchema, ISchema, SSchema>[]> {
1608
+ ): Block<BSchema, ISchema, SSchema>[] {
1609
1609
  return HTMLToBlocks(html, this.pmSchema);
1610
1610
  }
1611
1611
 
@@ -1615,9 +1615,9 @@ export class BlockNoteEditor<
1615
1615
  * @param blocks An array of blocks that should be serialized into Markdown.
1616
1616
  * @returns The blocks, serialized as a Markdown string.
1617
1617
  */
1618
- public async blocksToMarkdownLossy(
1618
+ public blocksToMarkdownLossy(
1619
1619
  blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,
1620
- ): Promise<string> {
1620
+ ): string {
1621
1621
  return blocksToMarkdown(blocks, this.pmSchema, this, {});
1622
1622
  }
1623
1623
 
@@ -1832,14 +1832,6 @@ export class BlockNoteEditor<
1832
1832
  this.showSelectionPlugin.setEnabled(forceSelectionVisible);
1833
1833
  }
1834
1834
 
1835
- /**
1836
- * This will convert HTML into a format that is compatible with BlockNote.
1837
- */
1838
- private convertHtmlToBlockNoteHtml(html: string) {
1839
- const htmlNode = nestedListsToBlockNoteStructure(html.trim());
1840
- return htmlNode.innerHTML;
1841
- }
1842
-
1843
1835
  /**
1844
1836
  * Paste HTML into the editor. Defaults to converting HTML to BlockNote HTML.
1845
1837
  * @param html The HTML to paste.
@@ -1848,7 +1840,8 @@ export class BlockNoteEditor<
1848
1840
  public pasteHTML(html: string, raw = false) {
1849
1841
  let htmlToPaste = html;
1850
1842
  if (!raw) {
1851
- htmlToPaste = this.convertHtmlToBlockNoteHtml(html);
1843
+ const blocks = this.tryParseHTMLToBlocks(html);
1844
+ htmlToPaste = this.blocksToFullHTML(blocks);
1852
1845
  }
1853
1846
  if (!htmlToPaste) {
1854
1847
  return;
@@ -1868,7 +1861,8 @@ export class BlockNoteEditor<
1868
1861
  * Paste markdown into the editor.
1869
1862
  * @param markdown The markdown to paste.
1870
1863
  */
1871
- public async pasteMarkdown(markdown: string) {
1872
- return this.pasteHTML(await markdownToHTML(markdown));
1864
+ public pasteMarkdown(markdown: string) {
1865
+ const html = markdownToHTML(markdown);
1866
+ return this.pasteHTML(html);
1873
1867
  }
1874
1868
  }