@blocknote/core 0.23.0 → 0.23.2-hotfix.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.
- package/dist/blocknote.js +2921 -2603
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +6 -6
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +3 -3
- package/src/api/blockManipulation/commands/updateBlock/updateBlock.ts +4 -2
- package/src/api/exporters/html/__snapshots__/codeBlock/contains-newlines/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/codeBlock/contains-newlines/internal.html +3 -0
- package/src/api/exporters/html/util/serializeBlocksInternalHTML.ts +6 -2
- package/src/api/exporters/markdown/__snapshots__/codeBlock/contains-newlines/markdown.md +4 -0
- package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +27 -0
- package/src/api/nodeConversions/blockToNode.ts +35 -9
- package/src/api/testUtil/cases/defaultSchema.ts +9 -0
- package/src/editor/BlockNoteEditor.ts +20 -12
- package/src/editor/BlockNoteExtensions.ts +4 -128
- package/src/extensions/Collaboration/createCollaborationExtensions.ts +144 -0
- package/src/extensions/SideMenu/SideMenuPlugin.ts +89 -28
- package/src/i18n/locales/fr.ts +2 -2
- package/src/i18n/locales/index.ts +2 -1
- package/src/i18n/locales/uk.ts +289 -0
- package/types/src/api/exporters/html/util/serializeBlocksInternalHTML.d.ts +1 -1
- package/types/src/api/nodeConversions/blockToNode.d.ts +1 -1
- package/types/src/editor/BlockNoteEditor.d.ts +3 -2
- package/types/src/editor/BlockNoteExtensions.d.ts +1 -1
- package/types/src/extensions/Collaboration/createCollaborationExtensions.d.ts +17 -0
- package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +1 -5
- package/types/src/i18n/locales/index.d.ts +2 -1
- package/types/src/i18n/locales/uk.d.ts +2 -0
- package/types/src/pm-nodes/BlockContainer.d.ts +1 -1
- package/types/src/pm-nodes/BlockGroup.d.ts +1 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import Collaboration from "@tiptap/extension-collaboration";
|
|
2
|
+
import { Awareness } from "y-protocols/awareness";
|
|
3
|
+
import CollaborationCursor from "@tiptap/extension-collaboration-cursor";
|
|
4
|
+
import * as Y from "yjs";
|
|
5
|
+
|
|
6
|
+
export const createCollaborationExtensions = (collaboration: {
|
|
7
|
+
fragment: Y.XmlFragment;
|
|
8
|
+
user: {
|
|
9
|
+
name: string;
|
|
10
|
+
color: string;
|
|
11
|
+
[key: string]: string;
|
|
12
|
+
};
|
|
13
|
+
provider: any;
|
|
14
|
+
renderCursor?: (user: any) => HTMLElement;
|
|
15
|
+
showCursorLabels?: "always" | "activity";
|
|
16
|
+
}) => {
|
|
17
|
+
const tiptapExtensions = [];
|
|
18
|
+
|
|
19
|
+
tiptapExtensions.push(
|
|
20
|
+
Collaboration.configure({
|
|
21
|
+
fragment: collaboration.fragment,
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const awareness = collaboration.provider?.awareness as Awareness | undefined;
|
|
26
|
+
|
|
27
|
+
if (awareness) {
|
|
28
|
+
const cursors = new Map<
|
|
29
|
+
number,
|
|
30
|
+
{ element: HTMLElement; hideTimeout: NodeJS.Timeout | undefined }
|
|
31
|
+
>();
|
|
32
|
+
|
|
33
|
+
if (collaboration.showCursorLabels !== "always") {
|
|
34
|
+
awareness.on(
|
|
35
|
+
"change",
|
|
36
|
+
({
|
|
37
|
+
updated,
|
|
38
|
+
}: {
|
|
39
|
+
added: Array<number>;
|
|
40
|
+
updated: Array<number>;
|
|
41
|
+
removed: Array<number>;
|
|
42
|
+
}) => {
|
|
43
|
+
for (const clientID of updated) {
|
|
44
|
+
const cursor = cursors.get(clientID);
|
|
45
|
+
|
|
46
|
+
if (cursor) {
|
|
47
|
+
cursor.element.setAttribute("data-active", "");
|
|
48
|
+
|
|
49
|
+
if (cursor.hideTimeout) {
|
|
50
|
+
clearTimeout(cursor.hideTimeout);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
cursors.set(clientID, {
|
|
54
|
+
element: cursor.element,
|
|
55
|
+
hideTimeout: setTimeout(() => {
|
|
56
|
+
cursor.element.removeAttribute("data-active");
|
|
57
|
+
}, 2000),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const renderCursor = (user: { name: string; color: string }) => {
|
|
66
|
+
const cursorElement = document.createElement("span");
|
|
67
|
+
|
|
68
|
+
cursorElement.classList.add("collaboration-cursor__caret");
|
|
69
|
+
cursorElement.setAttribute("style", `border-color: ${user.color}`);
|
|
70
|
+
if (collaboration?.showCursorLabels === "always") {
|
|
71
|
+
cursorElement.setAttribute("data-active", "");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const labelElement = document.createElement("span");
|
|
75
|
+
|
|
76
|
+
labelElement.classList.add("collaboration-cursor__label");
|
|
77
|
+
labelElement.setAttribute("style", `background-color: ${user.color}`);
|
|
78
|
+
labelElement.insertBefore(document.createTextNode(user.name), null);
|
|
79
|
+
|
|
80
|
+
cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space
|
|
81
|
+
cursorElement.insertBefore(labelElement, null);
|
|
82
|
+
cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space
|
|
83
|
+
|
|
84
|
+
return cursorElement;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const render = (
|
|
88
|
+
user: { color: string; name: string },
|
|
89
|
+
clientID: number
|
|
90
|
+
) => {
|
|
91
|
+
let cursorData = cursors.get(clientID);
|
|
92
|
+
|
|
93
|
+
if (!cursorData) {
|
|
94
|
+
const cursorElement =
|
|
95
|
+
collaboration?.renderCursor?.(user) || renderCursor(user);
|
|
96
|
+
|
|
97
|
+
if (collaboration?.showCursorLabels !== "always") {
|
|
98
|
+
cursorElement.addEventListener("mouseenter", () => {
|
|
99
|
+
const cursor = cursors.get(clientID)!;
|
|
100
|
+
cursor.element.setAttribute("data-active", "");
|
|
101
|
+
|
|
102
|
+
if (cursor.hideTimeout) {
|
|
103
|
+
clearTimeout(cursor.hideTimeout);
|
|
104
|
+
cursors.set(clientID, {
|
|
105
|
+
element: cursor.element,
|
|
106
|
+
hideTimeout: undefined,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
cursorElement.addEventListener("mouseleave", () => {
|
|
112
|
+
const cursor = cursors.get(clientID)!;
|
|
113
|
+
|
|
114
|
+
cursors.set(clientID, {
|
|
115
|
+
element: cursor.element,
|
|
116
|
+
hideTimeout: setTimeout(() => {
|
|
117
|
+
cursor.element.removeAttribute("data-active");
|
|
118
|
+
}, 2000),
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
cursorData = {
|
|
124
|
+
element: cursorElement,
|
|
125
|
+
hideTimeout: undefined,
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
cursors.set(clientID, cursorData);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return cursorData.element;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
tiptapExtensions.push(
|
|
135
|
+
CollaborationCursor.configure({
|
|
136
|
+
user: collaboration.user,
|
|
137
|
+
render: render as any, // tiptap type not compatible with latest y-prosemirror
|
|
138
|
+
provider: collaboration.provider,
|
|
139
|
+
})
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return tiptapExtensions;
|
|
144
|
+
};
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { DOMParser, Slice } from "@tiptap/pm/model";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
EditorState,
|
|
4
|
+
Plugin,
|
|
5
|
+
PluginKey,
|
|
6
|
+
TextSelection,
|
|
7
|
+
PluginView,
|
|
8
|
+
} from "@tiptap/pm/state";
|
|
3
9
|
import { EditorView } from "@tiptap/pm/view";
|
|
4
10
|
|
|
5
11
|
import { Block } from "../../blocks/defaultBlocks.js";
|
|
@@ -187,6 +193,11 @@ export class SideMenuView<
|
|
|
187
193
|
this.onKeyDown as EventListener,
|
|
188
194
|
true
|
|
189
195
|
);
|
|
196
|
+
|
|
197
|
+
// Setting capture=true ensures that any parent container of the editor that
|
|
198
|
+
// gets scrolled will trigger the scroll event. Scroll events do not bubble
|
|
199
|
+
// and so won't propagate to the document by default.
|
|
200
|
+
pmView.root.addEventListener("scroll", this.onScroll, true);
|
|
190
201
|
}
|
|
191
202
|
|
|
192
203
|
updateState = (state: SideMenuState<BSchema, I, S>) => {
|
|
@@ -263,21 +274,56 @@ export class SideMenuView<
|
|
|
263
274
|
}
|
|
264
275
|
};
|
|
265
276
|
|
|
266
|
-
/**
|
|
267
|
-
* If the event is outside the editor contents,
|
|
268
|
-
* we dispatch a fake event, so that we can still drop the content
|
|
269
|
-
* when dragging / dropping to the side of the editor
|
|
270
|
-
*/
|
|
271
277
|
onDrop = (event: DragEvent) => {
|
|
278
|
+
// Content from outside a BlockNote editor is being dropped - just let
|
|
279
|
+
// ProseMirror's default behaviour handle it.
|
|
280
|
+
if (this.pmView.dragging === null) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
272
284
|
this.editor._tiptapEditor.commands.blur();
|
|
273
285
|
|
|
274
|
-
// ProseMirror
|
|
275
|
-
//
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
if (this.isDragOrigin &&
|
|
279
|
-
|
|
286
|
+
// When ProseMirror handles a drop event on the editor while
|
|
287
|
+
// `view.dragging` is set, it deletes the selected content. However, if
|
|
288
|
+
// a block from a different editor is being dropped, this causes some
|
|
289
|
+
// issues that the code below fixes:
|
|
290
|
+
if (!this.isDragOrigin && this.pmView.dom.contains(event.target as Node)) {
|
|
291
|
+
// 1. Because the editor selection is unrelated to the dragged content,
|
|
292
|
+
// we don't want PM to delete its content. Therefore, we collapse the
|
|
293
|
+
// selection.
|
|
294
|
+
this.pmView.dispatch(
|
|
295
|
+
this.pmView.state.tr.setSelection(
|
|
296
|
+
TextSelection.create(
|
|
297
|
+
this.pmView.state.tr.doc,
|
|
298
|
+
this.pmView.state.tr.selection.to
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
);
|
|
302
|
+
} else if (
|
|
303
|
+
this.isDragOrigin &&
|
|
304
|
+
!this.pmView.dom.contains(event.target as Node)
|
|
305
|
+
) {
|
|
306
|
+
// 2. Because the editor from which the block originates doesn't get a
|
|
307
|
+
// drop event on it, PM doesn't delete its selected content. Therefore, we
|
|
308
|
+
// need to do so manually.
|
|
309
|
+
//
|
|
310
|
+
// Note: Deleting the selected content from the editor from which the
|
|
311
|
+
// block originates, may change its height. This can cause the position of
|
|
312
|
+
// the editor in which the block is being dropping to shift, before it
|
|
313
|
+
// can handle the drop event. That in turn can cause the drop to happen
|
|
314
|
+
// somewhere other than the user intended. To get around this, we delay
|
|
315
|
+
// deleting the selected content until all editors have had the chance to
|
|
316
|
+
// handle the event.
|
|
317
|
+
setTimeout(
|
|
318
|
+
() => this.pmView.dispatch(this.pmView.state.tr.deleteSelection()),
|
|
319
|
+
0
|
|
320
|
+
);
|
|
280
321
|
}
|
|
322
|
+
// 3. PM only clears `view.dragging` on the editor that the block was
|
|
323
|
+
// dropped, so we manually have to clear it on all the others. However,
|
|
324
|
+
// PM also needs to read `view.dragging` while handling the event, so we
|
|
325
|
+
// use a `setTimeout` to ensure it's only cleared after that.
|
|
326
|
+
setTimeout(() => (this.pmView.dragging = null), 0);
|
|
281
327
|
|
|
282
328
|
if (
|
|
283
329
|
this.sideMenuDetection === "editor" ||
|
|
@@ -293,6 +339,11 @@ export class SideMenuView<
|
|
|
293
339
|
});
|
|
294
340
|
|
|
295
341
|
if (!pos || pos.inside === -1) {
|
|
342
|
+
/**
|
|
343
|
+
* When `this.sideMenuSelection === "viewport"`, if the event is outside the
|
|
344
|
+
* editor contents, we dispatch a fake event, so that we can still drop the
|
|
345
|
+
* content when dragging / dropping to the side of the editor
|
|
346
|
+
*/
|
|
296
347
|
const evt = this.createSyntheticEvent(event);
|
|
297
348
|
// console.log("dispatch fake drop");
|
|
298
349
|
this.pmView.dom.dispatchEvent(evt);
|
|
@@ -318,25 +369,27 @@ export class SideMenuView<
|
|
|
318
369
|
* access `dataTransfer` contents on `dragstart` and `drop` events.
|
|
319
370
|
*/
|
|
320
371
|
onDragStart = (event: DragEvent) => {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
372
|
+
const html = event.dataTransfer?.getData("blocknote/html");
|
|
373
|
+
if (!html) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
326
376
|
|
|
327
|
-
|
|
328
|
-
|
|
377
|
+
if (this.pmView.dragging) {
|
|
378
|
+
throw new Error("New drag was started while an existing drag is ongoing");
|
|
379
|
+
}
|
|
329
380
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
topNode: this.pmView.state.schema.nodes["blockGroup"].create(),
|
|
333
|
-
});
|
|
381
|
+
const element = document.createElement("div");
|
|
382
|
+
element.innerHTML = html;
|
|
334
383
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
384
|
+
const parser = DOMParser.fromSchema(this.pmView.state.schema);
|
|
385
|
+
const node = parser.parse(element, {
|
|
386
|
+
topNode: this.pmView.state.schema.nodes["blockGroup"].create(),
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
this.pmView.dragging = {
|
|
390
|
+
slice: new Slice(node.content, 0, 0),
|
|
391
|
+
move: true,
|
|
392
|
+
};
|
|
340
393
|
};
|
|
341
394
|
|
|
342
395
|
/**
|
|
@@ -473,6 +526,13 @@ export class SideMenuView<
|
|
|
473
526
|
return evt;
|
|
474
527
|
}
|
|
475
528
|
|
|
529
|
+
onScroll = () => {
|
|
530
|
+
if (this.state?.show) {
|
|
531
|
+
this.state.referencePos = this.hoveredBlock!.getBoundingClientRect();
|
|
532
|
+
this.emitUpdate(this.state);
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
|
|
476
536
|
// Needed in cases where the editor state updates without the mouse cursor
|
|
477
537
|
// moving, as some state updates can require a side menu update. For example,
|
|
478
538
|
// adding a button to the side menu which removes the block can cause the
|
|
@@ -515,6 +575,7 @@ export class SideMenuView<
|
|
|
515
575
|
this.onKeyDown as EventListener,
|
|
516
576
|
true
|
|
517
577
|
);
|
|
578
|
+
this.pmView.root.removeEventListener("scroll", this.onScroll, true);
|
|
518
579
|
}
|
|
519
580
|
}
|
|
520
581
|
|
package/src/i18n/locales/fr.ts
CHANGED
|
@@ -281,11 +281,11 @@ export const fr: Dictionary = {
|
|
|
281
281
|
tooltip: "Basculer l'aperçu",
|
|
282
282
|
},
|
|
283
283
|
nest: {
|
|
284
|
-
tooltip: "
|
|
284
|
+
tooltip: "Augmenter le retrait du bloc",
|
|
285
285
|
secondary_tooltip: "Tab",
|
|
286
286
|
},
|
|
287
287
|
unnest: {
|
|
288
|
-
tooltip: "
|
|
288
|
+
tooltip: "Diminuer le retait du bloc",
|
|
289
289
|
secondary_tooltip: "Shift+Tab",
|
|
290
290
|
},
|
|
291
291
|
align_left: {
|
|
@@ -5,12 +5,13 @@ export * from "./es.js";
|
|
|
5
5
|
export * from "./fr.js";
|
|
6
6
|
export * from "./hr.js";
|
|
7
7
|
export * from "./is.js";
|
|
8
|
+
export * from "./it.js";
|
|
8
9
|
export * from "./ja.js";
|
|
9
10
|
export * from "./ko.js";
|
|
10
11
|
export * from "./nl.js";
|
|
11
12
|
export * from "./pl.js";
|
|
12
13
|
export * from "./pt.js";
|
|
13
14
|
export * from "./ru.js";
|
|
15
|
+
export * from "./uk.js";
|
|
14
16
|
export * from "./vi.js";
|
|
15
17
|
export * from "./zh.js";
|
|
16
|
-
export * from "./it.js"
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { Dictionary } from "../dictionary.js";
|
|
2
|
+
|
|
3
|
+
export const uk: Dictionary = {
|
|
4
|
+
slash_menu: {
|
|
5
|
+
heading: {
|
|
6
|
+
title: "Заголовок 1",
|
|
7
|
+
subtext: "Заголовок найвищого рівня",
|
|
8
|
+
aliases: ["h", "heading1", "h1", "заголовок1"],
|
|
9
|
+
group: "Заголовки",
|
|
10
|
+
},
|
|
11
|
+
heading_2: {
|
|
12
|
+
title: "Заголовок 2",
|
|
13
|
+
subtext: "Основний заголовок розділу",
|
|
14
|
+
aliases: ["h2", "heading2", "subheading", "заголовок2"],
|
|
15
|
+
group: "Заголовки",
|
|
16
|
+
},
|
|
17
|
+
heading_3: {
|
|
18
|
+
title: "Заголовок 3",
|
|
19
|
+
subtext: "Підзаголовок і груповий заголовок",
|
|
20
|
+
aliases: ["h3", "heading3", "subheading", "заголовок3"],
|
|
21
|
+
group: "Заголовки",
|
|
22
|
+
},
|
|
23
|
+
numbered_list: {
|
|
24
|
+
title: "Нумерований список",
|
|
25
|
+
subtext: "Список із впорядкованими елементами",
|
|
26
|
+
aliases: ["ol", "li", "list", "numberedlist", "numbered list", "список", "нумерований список"],
|
|
27
|
+
group: "Базові блоки",
|
|
28
|
+
},
|
|
29
|
+
bullet_list: {
|
|
30
|
+
title: "Маркований список",
|
|
31
|
+
subtext: "Список із невпорядкованими елементами",
|
|
32
|
+
aliases: ["ul", "li", "list", "bulletlist", "bullet list", "список", "маркований список"],
|
|
33
|
+
group: "Базові блоки",
|
|
34
|
+
},
|
|
35
|
+
check_list: {
|
|
36
|
+
title: "Чек-лист",
|
|
37
|
+
subtext: "Список із чекбоксами",
|
|
38
|
+
aliases: ["ul", "li", "list", "checklist", "check list", "checked list", "checkbox", "чекбокс", "чек-лист"],
|
|
39
|
+
group: "Базові блоки",
|
|
40
|
+
},
|
|
41
|
+
paragraph: {
|
|
42
|
+
title: "Параграф",
|
|
43
|
+
subtext: "Основний текст документа",
|
|
44
|
+
aliases: ["p", "paragraph", "параграф"],
|
|
45
|
+
group: "Базові блоки",
|
|
46
|
+
},
|
|
47
|
+
code_block: {
|
|
48
|
+
title: "Блок коду",
|
|
49
|
+
subtext: "Блок коду з підсвіткою синтаксису",
|
|
50
|
+
aliases: ["code", "pre", "блок коду"],
|
|
51
|
+
group: "Базові блоки",
|
|
52
|
+
},
|
|
53
|
+
page_break: {
|
|
54
|
+
title: "Розрив сторінки",
|
|
55
|
+
subtext: "Роздільник сторінки",
|
|
56
|
+
aliases: ["page", "break", "separator", "розрив сторінки", "розділювач"],
|
|
57
|
+
group: "Базові блоки",
|
|
58
|
+
},
|
|
59
|
+
table: {
|
|
60
|
+
title: "Таблиця",
|
|
61
|
+
subtext: "Таблиця з редагованими клітинками",
|
|
62
|
+
aliases: ["table", "таблиця"],
|
|
63
|
+
group: "Розширені",
|
|
64
|
+
},
|
|
65
|
+
image: {
|
|
66
|
+
title: "Зображення",
|
|
67
|
+
subtext: "Масштабоване зображення з підписом",
|
|
68
|
+
aliases: ["image", "imageUpload", "upload", "img", "picture", "media", "url", "зображення", "медіа"],
|
|
69
|
+
group: "Медіа",
|
|
70
|
+
},
|
|
71
|
+
video: {
|
|
72
|
+
title: "Відео",
|
|
73
|
+
subtext: "Масштабоване відео з підписом",
|
|
74
|
+
aliases: ["video", "videoUpload", "upload", "mp4", "film", "media", "url", "відео", "медіа"],
|
|
75
|
+
group: "Медіа",
|
|
76
|
+
},
|
|
77
|
+
audio: {
|
|
78
|
+
title: "Аудіо",
|
|
79
|
+
subtext: "Вбудоване аудіо з підписом",
|
|
80
|
+
aliases: ["audio", "audioUpload", "upload", "mp3", "sound", "media", "url", "аудіо", "медіа"],
|
|
81
|
+
group: "Медіа",
|
|
82
|
+
},
|
|
83
|
+
file: {
|
|
84
|
+
title: "Файл",
|
|
85
|
+
subtext: "Вбудований файл",
|
|
86
|
+
aliases: ["file", "upload", "embed", "media", "url", "файл", "медіа"],
|
|
87
|
+
group: "Медіа",
|
|
88
|
+
},
|
|
89
|
+
emoji: {
|
|
90
|
+
title: "Емодзі",
|
|
91
|
+
subtext: "Пошук і вставка емодзі",
|
|
92
|
+
aliases: ["emoji", "emote", "emotion", "face", "смайлик", "емодзі"],
|
|
93
|
+
group: "Інше",
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
placeholders: {
|
|
97
|
+
default: "Введіть текст або наберіть '/' для команд",
|
|
98
|
+
heading: "Заголовок",
|
|
99
|
+
bulletListItem: "Список",
|
|
100
|
+
numberedListItem: "Список",
|
|
101
|
+
checkListItem: "Список",
|
|
102
|
+
},
|
|
103
|
+
file_blocks: {
|
|
104
|
+
image: {
|
|
105
|
+
add_button_text: "Додати зображення",
|
|
106
|
+
},
|
|
107
|
+
video: {
|
|
108
|
+
add_button_text: "Додати відео",
|
|
109
|
+
},
|
|
110
|
+
audio: {
|
|
111
|
+
add_button_text: "Додати аудіо",
|
|
112
|
+
},
|
|
113
|
+
file: {
|
|
114
|
+
add_button_text: "Додати файл",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
// from react package:
|
|
118
|
+
side_menu: {
|
|
119
|
+
add_block_label: "Додати блок",
|
|
120
|
+
drag_handle_label: "Відкрити меню блока",
|
|
121
|
+
},
|
|
122
|
+
drag_handle: {
|
|
123
|
+
delete_menuitem: "Видалити",
|
|
124
|
+
colors_menuitem: "Кольори",
|
|
125
|
+
},
|
|
126
|
+
table_handle: {
|
|
127
|
+
delete_column_menuitem: "Видалити стовпець",
|
|
128
|
+
delete_row_menuitem: "Видалити рядок",
|
|
129
|
+
add_left_menuitem: "Додати стовпець зліва",
|
|
130
|
+
add_right_menuitem: "Додати стовпець справа",
|
|
131
|
+
add_above_menuitem: "Додати рядок вище",
|
|
132
|
+
add_below_menuitem: "Додати рядок нижче",
|
|
133
|
+
},
|
|
134
|
+
suggestion_menu: {
|
|
135
|
+
no_items_title: "Нічого не знайдено",
|
|
136
|
+
loading: "Завантаження…",
|
|
137
|
+
},
|
|
138
|
+
color_picker: {
|
|
139
|
+
text_title: "Текст",
|
|
140
|
+
background_title: "Фон",
|
|
141
|
+
colors: {
|
|
142
|
+
default: "За замовчуванням",
|
|
143
|
+
gray: "Сірий",
|
|
144
|
+
brown: "Коричневий",
|
|
145
|
+
red: "Червоний",
|
|
146
|
+
orange: "Помаранчевий",
|
|
147
|
+
yellow: "Жовтий",
|
|
148
|
+
green: "Зелений",
|
|
149
|
+
blue: "Блакитний",
|
|
150
|
+
purple: "Фіолетовий",
|
|
151
|
+
pink: "Рожевий",
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
formatting_toolbar: {
|
|
155
|
+
bold: {
|
|
156
|
+
tooltip: "Жирний",
|
|
157
|
+
secondary_tooltip: "Mod+B",
|
|
158
|
+
},
|
|
159
|
+
italic: {
|
|
160
|
+
tooltip: "Курсив",
|
|
161
|
+
secondary_tooltip: "Mod+I",
|
|
162
|
+
},
|
|
163
|
+
underline: {
|
|
164
|
+
tooltip: "Підкреслений",
|
|
165
|
+
secondary_tooltip: "Mod+U",
|
|
166
|
+
},
|
|
167
|
+
strike: {
|
|
168
|
+
tooltip: "Закреслений",
|
|
169
|
+
secondary_tooltip: "Mod+Shift+X",
|
|
170
|
+
},
|
|
171
|
+
code: {
|
|
172
|
+
tooltip: "Код",
|
|
173
|
+
secondary_tooltip: "",
|
|
174
|
+
},
|
|
175
|
+
colors: {
|
|
176
|
+
tooltip: "Кольори",
|
|
177
|
+
},
|
|
178
|
+
link: {
|
|
179
|
+
tooltip: "Створити посилання",
|
|
180
|
+
secondary_tooltip: "Mod+K",
|
|
181
|
+
},
|
|
182
|
+
file_caption: {
|
|
183
|
+
tooltip: "Редагувати підпис",
|
|
184
|
+
input_placeholder: "Редагувати підпис",
|
|
185
|
+
},
|
|
186
|
+
file_replace: {
|
|
187
|
+
tooltip: {
|
|
188
|
+
image: "Замінити зображення",
|
|
189
|
+
video: "Замінити відео",
|
|
190
|
+
audio: "Замінити аудіо",
|
|
191
|
+
file: "Замінити файл",
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
file_rename: {
|
|
195
|
+
tooltip: {
|
|
196
|
+
image: "Перейменувати зображення",
|
|
197
|
+
video: "Перейменувати відео",
|
|
198
|
+
audio: "Перейменувати аудіо",
|
|
199
|
+
file: "Перейменувати файл",
|
|
200
|
+
},
|
|
201
|
+
input_placeholder: {
|
|
202
|
+
image: "Перейменувати зображення",
|
|
203
|
+
video: "Перейменувати відео",
|
|
204
|
+
audio: "Перейменувати аудіо",
|
|
205
|
+
file: "Перейменувати файл",
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
file_download: {
|
|
209
|
+
tooltip: {
|
|
210
|
+
image: "Завантажити зображення",
|
|
211
|
+
video: "Завантажити відео",
|
|
212
|
+
audio: "Завантажити аудіо",
|
|
213
|
+
file: "Завантажити файл",
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
file_delete: {
|
|
217
|
+
tooltip: {
|
|
218
|
+
image: "Видалити зображення",
|
|
219
|
+
video: "Видалити відео",
|
|
220
|
+
audio: "Видалити аудіо",
|
|
221
|
+
file: "Видалити файл",
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
file_preview_toggle: {
|
|
225
|
+
tooltip: "Перемкнути попередній перегляд",
|
|
226
|
+
},
|
|
227
|
+
nest: {
|
|
228
|
+
tooltip: "Вкладений блок",
|
|
229
|
+
secondary_tooltip: "Tab",
|
|
230
|
+
},
|
|
231
|
+
unnest: {
|
|
232
|
+
tooltip: "Розгрупувати блок",
|
|
233
|
+
secondary_tooltip: "Shift+Tab",
|
|
234
|
+
},
|
|
235
|
+
align_left: {
|
|
236
|
+
tooltip: "Вирівняти за лівим краєм",
|
|
237
|
+
},
|
|
238
|
+
align_center: {
|
|
239
|
+
tooltip: "Вирівняти по центру",
|
|
240
|
+
},
|
|
241
|
+
align_right: {
|
|
242
|
+
tooltip: "Вирівняти за правим краєм",
|
|
243
|
+
},
|
|
244
|
+
align_justify: {
|
|
245
|
+
tooltip: "Вирівняти за шириною",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
file_panel: {
|
|
249
|
+
upload: {
|
|
250
|
+
title: "Завантажити",
|
|
251
|
+
file_placeholder: {
|
|
252
|
+
image: "Завантажити зображення",
|
|
253
|
+
video: "Завантажити відео",
|
|
254
|
+
audio: "Завантажити аудіо",
|
|
255
|
+
file: "Завантажити файл",
|
|
256
|
+
},
|
|
257
|
+
upload_error: "Помилка: не вдалося завантажити",
|
|
258
|
+
},
|
|
259
|
+
embed: {
|
|
260
|
+
title: "Вставити",
|
|
261
|
+
embed_button: {
|
|
262
|
+
image: "Вставити зображення",
|
|
263
|
+
video: "Вставити відео",
|
|
264
|
+
audio: "Вставити аудіо",
|
|
265
|
+
file: "Вставити файл",
|
|
266
|
+
},
|
|
267
|
+
url_placeholder: "Введіть URL",
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
link_toolbar: {
|
|
271
|
+
delete: {
|
|
272
|
+
tooltip: "Видалити посилання",
|
|
273
|
+
},
|
|
274
|
+
edit: {
|
|
275
|
+
text: "Редагувати посилання",
|
|
276
|
+
tooltip: "Редагувати",
|
|
277
|
+
},
|
|
278
|
+
open: {
|
|
279
|
+
tooltip: "Відкрити в новій вкладці",
|
|
280
|
+
},
|
|
281
|
+
form: {
|
|
282
|
+
title_placeholder: "Редагувати заголовок",
|
|
283
|
+
url_placeholder: "Редагувати URL",
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
generic: {
|
|
287
|
+
ctrl_shortcut: "Ctrl",
|
|
288
|
+
},
|
|
289
|
+
};
|
|
@@ -2,7 +2,7 @@ import { DOMSerializer } from "prosemirror-model";
|
|
|
2
2
|
import { PartialBlock } from "../../../../blocks/defaultBlocks.js";
|
|
3
3
|
import type { BlockNoteEditor } from "../../../../editor/BlockNoteEditor.js";
|
|
4
4
|
import { BlockSchema, InlineContentSchema, StyleSchema } from "../../../../schema/index.js";
|
|
5
|
-
export declare function serializeInlineContentInternalHTML<BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema>(editor: BlockNoteEditor<any, I, S>, blockContent: PartialBlock<BSchema, I, S>["content"], serializer: DOMSerializer, options?: {
|
|
5
|
+
export declare function serializeInlineContentInternalHTML<BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema>(editor: BlockNoteEditor<any, I, S>, blockContent: PartialBlock<BSchema, I, S>["content"], serializer: DOMSerializer, blockType?: string, options?: {
|
|
6
6
|
document?: Document;
|
|
7
7
|
}): HTMLElement | DocumentFragment;
|
|
8
8
|
export declare const serializeBlocksInternalHTML: <BSchema extends Record<string, import("../../../../schema/index.js").BlockConfig>, I extends InlineContentSchema, S extends StyleSchema>(editor: BlockNoteEditor<BSchema, I, S>, blocks: PartialBlock<BSchema, I, S>[], serializer: DOMSerializer, options?: {
|
|
@@ -4,7 +4,7 @@ import type { PartialBlock } from "../../blocks/defaultBlocks";
|
|
|
4
4
|
/**
|
|
5
5
|
* converts an array of inline content elements to prosemirror nodes
|
|
6
6
|
*/
|
|
7
|
-
export declare function inlineContentToNodes<I extends InlineContentSchema, S extends StyleSchema>(blockContent: PartialInlineContent<I, S>, schema: Schema, styleSchema: S): Node[];
|
|
7
|
+
export declare function inlineContentToNodes<I extends InlineContentSchema, S extends StyleSchema>(blockContent: PartialInlineContent<I, S>, schema: Schema, styleSchema: S, blockType?: string): Node[];
|
|
8
8
|
/**
|
|
9
9
|
* converts an array of inline content elements to prosemirror nodes
|
|
10
10
|
*/
|
|
@@ -16,8 +16,9 @@ import { BlockNoteSchema } from "./BlockNoteSchema.js";
|
|
|
16
16
|
import { BlockNoteTipTapEditor } from "./BlockNoteTipTapEditor.js";
|
|
17
17
|
import { Dictionary } from "../i18n/dictionary.js";
|
|
18
18
|
import { Plugin, Transaction } from "@tiptap/pm/state";
|
|
19
|
-
import "../style.css";
|
|
20
19
|
import { EditorView } from "prosemirror-view";
|
|
20
|
+
import "../style.css";
|
|
21
|
+
export type BlockNoteExtensionFactory = (editor: BlockNoteEditor<any, any, any>) => BlockNoteExtension;
|
|
21
22
|
export type BlockNoteExtension = AnyExtension | {
|
|
22
23
|
plugin: Plugin;
|
|
23
24
|
};
|
|
@@ -111,7 +112,7 @@ export type BlockNoteEditorOptions<BSchema extends BlockSchema, ISchema extends
|
|
|
111
112
|
/**
|
|
112
113
|
* (experimental) add extra prosemirror plugins or tiptap extensions to the editor
|
|
113
114
|
*/
|
|
114
|
-
_extensions: Record<string, BlockNoteExtension>;
|
|
115
|
+
_extensions: Record<string, BlockNoteExtension | BlockNoteExtensionFactory>;
|
|
115
116
|
trailingBlock?: boolean;
|
|
116
117
|
/**
|
|
117
118
|
* Boolean indicating whether the editor is in headless mode.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { BlockNoteEditor, BlockNoteExtension } from "./BlockNoteEditor.js";
|
|
2
1
|
import { Plugin } from "prosemirror-state";
|
|
3
2
|
import * as Y from "yjs";
|
|
3
|
+
import type { BlockNoteEditor, BlockNoteExtension } from "./BlockNoteEditor.js";
|
|
4
4
|
import { BlockNoteDOMAttributes, BlockSchema, BlockSpecs, InlineContentSchema, InlineContentSpecs, StyleSchema, StyleSpecs } from "../schema/index.js";
|
|
5
5
|
type ExtensionOptions<BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema> = {
|
|
6
6
|
editor: BlockNoteEditor<BSchema, I, S>;
|