@blocknote/core 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blocknote.js +12265 -12287
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +20 -20
- package/dist/blocknote.umd.cjs.map +1 -1
- package/package.json +2 -2
- package/src/BlockNoteEditor.ts +232 -10
- package/src/BlockNoteExtensions.ts +8 -4
- package/src/extensions/Blocks/api/cursorPositionTypes.ts +2 -0
- package/src/extensions/SlashMenu/BaseSlashMenuItem.ts +31 -0
- package/src/extensions/SlashMenu/SlashMenuExtension.ts +10 -7
- package/src/extensions/SlashMenu/{defaultSlashCommands.tsx → defaultSlashMenuItems.tsx} +59 -106
- package/src/extensions/SlashMenu/index.ts +3 -7
- package/src/index.ts +2 -3
- package/src/shared/plugins/suggestion/SuggestionItem.ts +2 -13
- package/src/shared/plugins/suggestion/SuggestionPlugin.ts +31 -18
- package/types/src/BlockNoteEditor.d.ts +80 -6
- package/types/src/BlockNoteExtensions.d.ts +5 -4
- package/types/src/extensions/Blocks/api/cursorPositionTypes.d.ts +2 -0
- package/types/src/extensions/SlashMenu/BaseSlashMenuItem.d.ts +20 -0
- package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +4 -2
- package/types/src/extensions/SlashMenu/defaultSlashMenuItems.d.ts +5 -0
- package/types/src/extensions/SlashMenu/index.d.ts +3 -3
- package/types/src/index.d.ts +2 -3
- package/types/src/shared/plugins/suggestion/SuggestionItem.d.ts +3 -11
- package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +4 -4
- package/src/api/Editor.ts +0 -226
- package/src/extensions/SlashMenu/SlashMenuItem.ts +0 -34
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
SuggestionsMenuStaticParams,
|
|
10
10
|
} from "./SuggestionsMenuFactoryTypes";
|
|
11
11
|
import { SuggestionItem } from "./SuggestionItem";
|
|
12
|
+
import { BlockNoteEditor } from "../../../BlockNoteEditor";
|
|
12
13
|
|
|
13
14
|
export type SuggestionPluginOptions<T extends SuggestionItem> = {
|
|
14
15
|
/**
|
|
@@ -19,9 +20,9 @@ export type SuggestionPluginOptions<T extends SuggestionItem> = {
|
|
|
19
20
|
pluginKey: PluginKey;
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
|
-
* The
|
|
23
|
+
* The BlockNote editor.
|
|
23
24
|
*/
|
|
24
|
-
editor:
|
|
25
|
+
editor: BlockNoteEditor;
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* The character that should trigger the suggestion menu to pop up (e.g. a '/' for commands), when typed by the user.
|
|
@@ -37,7 +38,7 @@ export type SuggestionPluginOptions<T extends SuggestionItem> = {
|
|
|
37
38
|
* this should be done manually. The `editor` and `range` properties passed
|
|
38
39
|
* to the callback function might come in handy when doing this.
|
|
39
40
|
*/
|
|
40
|
-
onSelectItem?: (props: { item: T; editor:
|
|
41
|
+
onSelectItem?: (props: { item: T; editor: BlockNoteEditor }) => void;
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* A function that should supply the plugin with items to suggest, based on a certain query string.
|
|
@@ -81,14 +82,14 @@ function getDefaultPluginState<
|
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
type SuggestionPluginViewOptions<T extends SuggestionItem> = {
|
|
84
|
-
editor:
|
|
85
|
+
editor: BlockNoteEditor;
|
|
85
86
|
pluginKey: PluginKey;
|
|
86
|
-
onSelectItem: (props: { item: T; editor:
|
|
87
|
+
onSelectItem: (props: { item: T; editor: BlockNoteEditor }) => void;
|
|
87
88
|
suggestionsMenuFactory: SuggestionsMenuFactory<T>;
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
class SuggestionPluginView<T extends SuggestionItem> {
|
|
91
|
-
editor:
|
|
92
|
+
editor: BlockNoteEditor;
|
|
92
93
|
pluginKey: PluginKey;
|
|
93
94
|
|
|
94
95
|
suggestionsMenu: SuggestionsMenu<T>;
|
|
@@ -107,17 +108,23 @@ class SuggestionPluginView<T extends SuggestionItem> {
|
|
|
107
108
|
|
|
108
109
|
this.pluginState = getDefaultPluginState<T>();
|
|
109
110
|
|
|
110
|
-
this.itemCallback = (item: T) =>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
this.itemCallback = (item: T) => {
|
|
112
|
+
editor._tiptapEditor
|
|
113
|
+
.chain()
|
|
114
|
+
.focus()
|
|
115
|
+
.deleteRange({
|
|
115
116
|
from:
|
|
116
117
|
this.pluginState.queryStartPos! -
|
|
117
118
|
this.pluginState.triggerCharacter!.length,
|
|
118
|
-
to: editor.state.selection.from,
|
|
119
|
-
}
|
|
119
|
+
to: editor._tiptapEditor.state.selection.from,
|
|
120
|
+
})
|
|
121
|
+
.run();
|
|
122
|
+
|
|
123
|
+
selectItemCallback({
|
|
124
|
+
item: item,
|
|
125
|
+
editor: editor,
|
|
120
126
|
});
|
|
127
|
+
};
|
|
121
128
|
|
|
122
129
|
this.suggestionsMenu = suggestionsMenuFactory(this.getStaticParams());
|
|
123
130
|
}
|
|
@@ -220,7 +227,7 @@ export function createSuggestionPlugin<T extends SuggestionItem>({
|
|
|
220
227
|
new SuggestionPluginView({
|
|
221
228
|
editor: editor,
|
|
222
229
|
pluginKey: pluginKey,
|
|
223
|
-
onSelectItem: (props: { item: T; editor:
|
|
230
|
+
onSelectItem: (props: { item: T; editor: BlockNoteEditor }) => {
|
|
224
231
|
deactivate(view);
|
|
225
232
|
selectItemCallback(props);
|
|
226
233
|
},
|
|
@@ -378,14 +385,20 @@ export function createSuggestionPlugin<T extends SuggestionItem>({
|
|
|
378
385
|
// Selects an item and closes the menu.
|
|
379
386
|
if (event.key === "Enter") {
|
|
380
387
|
deactivate(view);
|
|
388
|
+
editor._tiptapEditor
|
|
389
|
+
.chain()
|
|
390
|
+
.focus()
|
|
391
|
+
.deleteRange({
|
|
392
|
+
from: queryStartPos! - triggerCharacter!.length,
|
|
393
|
+
to: editor._tiptapEditor.state.selection.from,
|
|
394
|
+
})
|
|
395
|
+
.run();
|
|
396
|
+
|
|
381
397
|
selectItemCallback({
|
|
382
398
|
item: items[keyboardHoveredItemIndex],
|
|
383
399
|
editor: editor,
|
|
384
|
-
range: {
|
|
385
|
-
from: queryStartPos - triggerCharacter.length,
|
|
386
|
-
to: view.state.selection.from,
|
|
387
|
-
},
|
|
388
400
|
});
|
|
401
|
+
|
|
389
402
|
return true;
|
|
390
403
|
}
|
|
391
404
|
|
|
@@ -1,22 +1,96 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Editor as EditorAPI } from "./api/Editor";
|
|
1
|
+
import { Block, PartialBlock } from "./extensions/Blocks/api/blockTypes";
|
|
3
2
|
import { UiFactories } from "./BlockNoteExtensions";
|
|
4
|
-
import {
|
|
3
|
+
import { BaseSlashMenuItem } from "./extensions/SlashMenu";
|
|
4
|
+
import { Editor as TiptapEditor } from "@tiptap/core/dist/packages/core/src/Editor";
|
|
5
|
+
import { TextCursorPosition } from "./extensions/Blocks/api/cursorPositionTypes";
|
|
5
6
|
export type BlockNoteEditorOptions = {
|
|
6
7
|
enableBlockNoteExtensions: boolean;
|
|
7
8
|
disableHistoryExtension: boolean;
|
|
8
9
|
uiFactories: UiFactories;
|
|
9
|
-
slashCommands:
|
|
10
|
+
slashCommands: BaseSlashMenuItem[];
|
|
10
11
|
parentElement: HTMLElement;
|
|
11
12
|
editorDOMAttributes: Record<string, string>;
|
|
12
13
|
onUpdate: (editor: BlockNoteEditor) => void;
|
|
13
14
|
onCreate: (editor: BlockNoteEditor) => void;
|
|
14
15
|
_tiptapOptions: any;
|
|
15
16
|
};
|
|
16
|
-
export declare class BlockNoteEditor
|
|
17
|
-
readonly _tiptapEditor:
|
|
17
|
+
export declare class BlockNoteEditor {
|
|
18
|
+
readonly _tiptapEditor: TiptapEditor & {
|
|
18
19
|
contentComponent: any;
|
|
19
20
|
};
|
|
21
|
+
private blockCache;
|
|
20
22
|
get domElement(): HTMLDivElement;
|
|
21
23
|
constructor(options?: Partial<BlockNoteEditorOptions>);
|
|
24
|
+
/**
|
|
25
|
+
* Gets a list of all top-level blocks that are in the editor.
|
|
26
|
+
*/
|
|
27
|
+
get topLevelBlocks(): Block[];
|
|
28
|
+
/**
|
|
29
|
+
* Traverses all blocks in the editor, including all nested blocks, and executes a callback for each. The traversal is
|
|
30
|
+
* depth-first, which is the same order as blocks appear in the editor by y-coordinate.
|
|
31
|
+
* @param callback The callback to execute for each block.
|
|
32
|
+
* @param reverse Whether the blocks should be traversed in reverse order.
|
|
33
|
+
*/
|
|
34
|
+
allBlocks(callback: (block: Block) => void, reverse?: boolean): void;
|
|
35
|
+
/**
|
|
36
|
+
* Gets information regarding the position of the text cursor in the editor.
|
|
37
|
+
*/
|
|
38
|
+
getTextCursorPosition(): TextCursorPosition;
|
|
39
|
+
setTextCursorPosition(block: Block, placement?: "start" | "end"): void;
|
|
40
|
+
/**
|
|
41
|
+
* Inserts multiple blocks before, after, or nested inside an existing block in the editor.
|
|
42
|
+
* @param blocksToInsert An array of blocks to insert.
|
|
43
|
+
* @param blockToInsertAt An existing block, marking where the new blocks should be inserted at.
|
|
44
|
+
* @param placement Determines whether the blocks should be inserted just before, just after, or nested inside the
|
|
45
|
+
* existing block.
|
|
46
|
+
*/
|
|
47
|
+
insertBlocks(blocksToInsert: PartialBlock[], blockToInsertAt: Block, placement?: "before" | "after" | "nested"): void;
|
|
48
|
+
/**
|
|
49
|
+
* Updates a block in the editor to the given specification.
|
|
50
|
+
* @param blockToUpdate The block that should be updated.
|
|
51
|
+
* @param updatedBlock The specification that the block should be updated to.
|
|
52
|
+
*/
|
|
53
|
+
updateBlock(blockToUpdate: Block, updatedBlock: PartialBlock): void;
|
|
54
|
+
/**
|
|
55
|
+
* Removes multiple blocks from the editor. Throws an error if any of the blocks could not be found.
|
|
56
|
+
* @param blocksToRemove An array of blocks that should be removed.
|
|
57
|
+
*/
|
|
58
|
+
removeBlocks(blocksToRemove: Block[]): void;
|
|
59
|
+
/**
|
|
60
|
+
* Replaces multiple blocks in the editor with several other blocks. If the provided blocks to remove are not adjacent
|
|
61
|
+
* to each other, the new blocks are inserted at the position of the first block in the array. Throws an error if any
|
|
62
|
+
* of the blocks could not be found.
|
|
63
|
+
* @param blocksToRemove An array of blocks that should be replaced.
|
|
64
|
+
* @param blocksToInsert An array of blocks to replace the old ones with.
|
|
65
|
+
*/
|
|
66
|
+
replaceBlocks(blocksToRemove: Block[], blocksToInsert: PartialBlock[]): void;
|
|
67
|
+
/**
|
|
68
|
+
* Executes a callback function whenever the editor's content changes.
|
|
69
|
+
* @param callback The callback function to execute.
|
|
70
|
+
*/
|
|
71
|
+
onContentChange(callback: () => void): void;
|
|
72
|
+
/**
|
|
73
|
+
* Serializes a list of blocks into an HTML string. The output is not the same as what's rendered by the editor, and
|
|
74
|
+
* is simplified in order to better conform to HTML standards. Block structuring elements are removed, children of
|
|
75
|
+
* blocks which aren't list items are lifted out of them, and list items blocks are wrapped in `ul`/`ol` tags.
|
|
76
|
+
* @param blocks The list of blocks to serialize into HTML.
|
|
77
|
+
*/
|
|
78
|
+
blocksToHTML(blocks: Block[]): Promise<string>;
|
|
79
|
+
/**
|
|
80
|
+
* Creates a list of blocks from an HTML string.
|
|
81
|
+
* @param htmlString The HTML string to create a list of blocks from.
|
|
82
|
+
*/
|
|
83
|
+
HTMLToBlocks(htmlString: string): Promise<Block[]>;
|
|
84
|
+
/**
|
|
85
|
+
* Serializes a list of blocks into a Markdown string. The output is simplified as Markdown does not support all
|
|
86
|
+
* features of BlockNote. Block structuring elements are removed, children of blocks which aren't list items are
|
|
87
|
+
* lifted out of them, and certain styles are removed.
|
|
88
|
+
* @param blocks The list of blocks to serialize into Markdown.
|
|
89
|
+
*/
|
|
90
|
+
blocksToMarkdown(blocks: Block[]): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Creates a list of blocks from a Markdown string.
|
|
93
|
+
* @param markdownString The Markdown string to create a list of blocks from.
|
|
94
|
+
*/
|
|
95
|
+
markdownToBlocks(markdownString: string): Promise<Block[]>;
|
|
22
96
|
}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { Extensions } from "@tiptap/core";
|
|
2
|
+
import { BlockNoteEditor } from "./BlockNoteEditor";
|
|
2
3
|
import { BlockSideMenuFactory } from "./extensions/DraggableBlocks/BlockSideMenuFactoryTypes";
|
|
3
4
|
import { FormattingToolbarFactory } from "./extensions/FormattingToolbar/FormattingToolbarFactoryTypes";
|
|
4
5
|
import { HyperlinkToolbarFactory } from "./extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes";
|
|
5
|
-
import {
|
|
6
|
-
import { SlashMenuItem } from "./extensions/SlashMenu/SlashMenuItem";
|
|
6
|
+
import { BaseSlashMenuItem } from "./extensions/SlashMenu";
|
|
7
7
|
import { SuggestionsMenuFactory } from "./shared/plugins/suggestion/SuggestionsMenuFactoryTypes";
|
|
8
8
|
export type UiFactories = Partial<{
|
|
9
9
|
formattingToolbarFactory: FormattingToolbarFactory;
|
|
10
10
|
hyperlinkToolbarFactory: HyperlinkToolbarFactory;
|
|
11
|
-
slashMenuFactory: SuggestionsMenuFactory<
|
|
11
|
+
slashMenuFactory: SuggestionsMenuFactory<BaseSlashMenuItem>;
|
|
12
12
|
blockSideMenuFactory: BlockSideMenuFactory;
|
|
13
13
|
}>;
|
|
14
14
|
/**
|
|
15
15
|
* Get all the Tiptap extensions BlockNote is configured with by default
|
|
16
16
|
*/
|
|
17
17
|
export declare const getBlockNoteExtensions: (opts: {
|
|
18
|
+
editor: BlockNoteEditor;
|
|
18
19
|
uiFactories: UiFactories;
|
|
19
|
-
slashCommands:
|
|
20
|
+
slashCommands: BaseSlashMenuItem[];
|
|
20
21
|
}) => Extensions;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SuggestionItem } from "../../shared/plugins/suggestion/SuggestionItem";
|
|
2
|
+
import { BlockNoteEditor } from "../../BlockNoteEditor";
|
|
3
|
+
/**
|
|
4
|
+
* A class that defines a slash command (/<command>).
|
|
5
|
+
*
|
|
6
|
+
* (Not to be confused with ProseMirror commands nor TipTap commands.)
|
|
7
|
+
*/
|
|
8
|
+
export declare class BaseSlashMenuItem extends SuggestionItem {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly execute: (editor: BlockNoteEditor) => void;
|
|
11
|
+
readonly aliases: string[];
|
|
12
|
+
/**
|
|
13
|
+
* Constructs a new slash-command.
|
|
14
|
+
*
|
|
15
|
+
* @param name The name of the command
|
|
16
|
+
* @param execute The callback for creating a new node
|
|
17
|
+
* @param aliases Aliases for this command
|
|
18
|
+
*/
|
|
19
|
+
constructor(name: string, execute: (editor: BlockNoteEditor) => void, aliases?: string[]);
|
|
20
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Extension } from "@tiptap/core";
|
|
2
2
|
import { PluginKey } from "prosemirror-state";
|
|
3
3
|
import { SuggestionsMenuFactory } from "../../shared/plugins/suggestion/SuggestionsMenuFactoryTypes";
|
|
4
|
-
import {
|
|
4
|
+
import { BaseSlashMenuItem } from "./BaseSlashMenuItem";
|
|
5
|
+
import { BlockNoteEditor } from "../../BlockNoteEditor";
|
|
5
6
|
export type SlashMenuOptions = {
|
|
6
|
-
|
|
7
|
+
editor: BlockNoteEditor | undefined;
|
|
8
|
+
commands: BaseSlashMenuItem[] | undefined;
|
|
7
9
|
slashMenuFactory: SuggestionsMenuFactory<any> | undefined;
|
|
8
10
|
};
|
|
9
11
|
export declare const SlashMenuPluginKey: PluginKey<any>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defaultSlashMenuItems } from "./defaultSlashMenuItems";
|
|
2
2
|
import { SlashMenuExtension } from "./SlashMenuExtension";
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
3
|
+
import { BaseSlashMenuItem } from "./BaseSlashMenuItem";
|
|
4
|
+
export { defaultSlashMenuItems, BaseSlashMenuItem, SlashMenuExtension };
|
package/types/src/index.d.ts
CHANGED
|
@@ -4,9 +4,8 @@ export * from "./extensions/Blocks/api/blockTypes";
|
|
|
4
4
|
export * from "./extensions/DraggableBlocks/BlockSideMenuFactoryTypes";
|
|
5
5
|
export * from "./extensions/FormattingToolbar/FormattingToolbarFactoryTypes";
|
|
6
6
|
export * from "./extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes";
|
|
7
|
-
export {
|
|
8
|
-
export * from "./extensions/SlashMenu/
|
|
7
|
+
export { defaultSlashMenuItems } from "./extensions/SlashMenu/defaultSlashMenuItems";
|
|
8
|
+
export * from "./extensions/SlashMenu/BaseSlashMenuItem";
|
|
9
9
|
export * from "./shared/EditorElement";
|
|
10
10
|
export type { SuggestionItem } from "./shared/plugins/suggestion/SuggestionItem";
|
|
11
11
|
export * from "./shared/plugins/suggestion/SuggestionsMenuFactoryTypes";
|
|
12
|
-
export * from "../src/api/Editor";
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A generic interface used in all suggestion menus (slash menu, mentions, etc)
|
|
3
3
|
*/
|
|
4
|
-
export
|
|
5
|
-
/**
|
|
6
|
-
* The name of the item
|
|
7
|
-
*/
|
|
4
|
+
export declare class SuggestionItem {
|
|
8
5
|
name: string;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* matches the query or **false** otherwise.
|
|
12
|
-
*
|
|
13
|
-
* @param query the query string
|
|
14
|
-
*/
|
|
15
|
-
match(query: string): boolean;
|
|
6
|
+
match: (query: string) => boolean;
|
|
7
|
+
constructor(name: string, match: (query: string) => boolean);
|
|
16
8
|
}
|
|
@@ -2,6 +2,7 @@ import { Editor, Range } from "@tiptap/core";
|
|
|
2
2
|
import { Plugin, PluginKey } from "prosemirror-state";
|
|
3
3
|
import { SuggestionsMenuFactory } from "./SuggestionsMenuFactoryTypes";
|
|
4
4
|
import { SuggestionItem } from "./SuggestionItem";
|
|
5
|
+
import { BlockNoteEditor } from "../../../BlockNoteEditor";
|
|
5
6
|
export type SuggestionPluginOptions<T extends SuggestionItem> = {
|
|
6
7
|
/**
|
|
7
8
|
* The name of the plugin.
|
|
@@ -10,9 +11,9 @@ export type SuggestionPluginOptions<T extends SuggestionItem> = {
|
|
|
10
11
|
*/
|
|
11
12
|
pluginKey: PluginKey;
|
|
12
13
|
/**
|
|
13
|
-
* The
|
|
14
|
+
* The BlockNote editor.
|
|
14
15
|
*/
|
|
15
|
-
editor:
|
|
16
|
+
editor: BlockNoteEditor;
|
|
16
17
|
/**
|
|
17
18
|
* The character that should trigger the suggestion menu to pop up (e.g. a '/' for commands), when typed by the user.
|
|
18
19
|
*/
|
|
@@ -27,8 +28,7 @@ export type SuggestionPluginOptions<T extends SuggestionItem> = {
|
|
|
27
28
|
*/
|
|
28
29
|
onSelectItem?: (props: {
|
|
29
30
|
item: T;
|
|
30
|
-
editor:
|
|
31
|
-
range: Range;
|
|
31
|
+
editor: BlockNoteEditor;
|
|
32
32
|
}) => void;
|
|
33
33
|
/**
|
|
34
34
|
* A function that should supply the plugin with items to suggest, based on a certain query string.
|
package/src/api/Editor.ts
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import { Editor as TiptapEditor } from "@tiptap/core";
|
|
2
|
-
import { Node } from "prosemirror-model";
|
|
3
|
-
import { getBlockInfoFromPos } from "../extensions/Blocks/helpers/getBlockInfoFromPos";
|
|
4
|
-
import {
|
|
5
|
-
Block,
|
|
6
|
-
BlockIdentifier,
|
|
7
|
-
PartialBlock,
|
|
8
|
-
} from "../extensions/Blocks/api/blockTypes";
|
|
9
|
-
import { TextCursorPosition } from "../extensions/Blocks/api/cursorPositionTypes";
|
|
10
|
-
import { nodeToBlock } from "./nodeConversions/nodeConversions";
|
|
11
|
-
import {
|
|
12
|
-
insertBlocks,
|
|
13
|
-
removeBlocks,
|
|
14
|
-
replaceBlocks,
|
|
15
|
-
updateBlock,
|
|
16
|
-
} from "./blockManipulation/blockManipulation";
|
|
17
|
-
import {
|
|
18
|
-
blocksToHTML,
|
|
19
|
-
blocksToMarkdown,
|
|
20
|
-
HTMLToBlocks,
|
|
21
|
-
markdownToBlocks,
|
|
22
|
-
} from "./formatConversions/formatConversions";
|
|
23
|
-
|
|
24
|
-
export class Editor {
|
|
25
|
-
constructor(
|
|
26
|
-
private tiptapEditor: TiptapEditor,
|
|
27
|
-
private blockCache = new WeakMap<Node, Block>()
|
|
28
|
-
) {}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Gets a snapshot of all top-level blocks that are in the editor.
|
|
32
|
-
* @returns An array containing a snapshot of all top-level (non-nested) blocks in the editor.
|
|
33
|
-
*/
|
|
34
|
-
public get topLevelBlocks(): Block[] {
|
|
35
|
-
const blocks: Block[] = [];
|
|
36
|
-
|
|
37
|
-
this.tiptapEditor.state.doc.firstChild!.descendants((node) => {
|
|
38
|
-
blocks.push(nodeToBlock(node, this.blockCache));
|
|
39
|
-
|
|
40
|
-
return false;
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
return blocks;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Retrieves a snapshot of an existing block from the editor.
|
|
48
|
-
* @param block The identifier of an existing block that should be retrieved.
|
|
49
|
-
* @returns The block that matches the identifier, or undefined if no matching block was found.
|
|
50
|
-
*/
|
|
51
|
-
public getBlock(block: BlockIdentifier): Block | undefined {
|
|
52
|
-
const id = typeof block === "string" ? block : block.id;
|
|
53
|
-
let newBlock: Block | undefined = undefined;
|
|
54
|
-
|
|
55
|
-
this.tiptapEditor.state.doc.firstChild!.descendants((node) => {
|
|
56
|
-
if (typeof newBlock !== "undefined") {
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (node.type.name !== "blockContainer" || node.attrs.id !== id) {
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
newBlock = nodeToBlock(node, this.blockCache);
|
|
65
|
-
|
|
66
|
-
return false;
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
return newBlock;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Traverses all blocks in the editor, including all nested blocks, and executes a callback for each. The traversal is
|
|
74
|
-
* depth-first, which is the same order as blocks appear in the editor by y-coordinate. Stops traversal if the callback
|
|
75
|
-
* returns false;
|
|
76
|
-
* @param callback The callback to execute for each block.
|
|
77
|
-
* @param reverse Whether the blocks should be traversed in reverse order.
|
|
78
|
-
*/
|
|
79
|
-
public forEachBlock(
|
|
80
|
-
callback: (block: Block) => boolean,
|
|
81
|
-
reverse: boolean = false
|
|
82
|
-
): void {
|
|
83
|
-
let stop = false;
|
|
84
|
-
|
|
85
|
-
function helper(blocks: Block[]) {
|
|
86
|
-
if (reverse) {
|
|
87
|
-
for (const block of blocks.reverse()) {
|
|
88
|
-
helper(block.children);
|
|
89
|
-
|
|
90
|
-
if (stop) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
stop = !callback(block);
|
|
95
|
-
|
|
96
|
-
if (stop) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
} else {
|
|
101
|
-
for (const block of blocks) {
|
|
102
|
-
stop = !callback(block);
|
|
103
|
-
|
|
104
|
-
if (stop) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
helper(block.children);
|
|
109
|
-
|
|
110
|
-
if (stop) {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
helper(this.topLevelBlocks);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Gets a snapshot of the text cursor position within the editor.
|
|
122
|
-
* @returns A snapshot of the text cursor position.
|
|
123
|
-
*/
|
|
124
|
-
public get textCursorPosition(): TextCursorPosition {
|
|
125
|
-
const { node } = getBlockInfoFromPos(
|
|
126
|
-
this.tiptapEditor.state.doc,
|
|
127
|
-
this.tiptapEditor.state.selection.from
|
|
128
|
-
)!;
|
|
129
|
-
|
|
130
|
-
return { block: nodeToBlock(node, this.blockCache) };
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Inserts multiple blocks before, after, or nested inside an existing block in the editor.
|
|
135
|
-
* @param blocksToInsert An array of blocks to insert.
|
|
136
|
-
* @param blockToInsertAt An existing block, marking where the new blocks should be inserted at.
|
|
137
|
-
* @param placement Determines whether the blocks should be inserted just before, just after, or nested inside the
|
|
138
|
-
* existing block.
|
|
139
|
-
*/
|
|
140
|
-
public insertBlocks(
|
|
141
|
-
blocksToInsert: PartialBlock[],
|
|
142
|
-
blockToInsertAt: Block,
|
|
143
|
-
placement: "before" | "after" | "nested" = "before"
|
|
144
|
-
): void {
|
|
145
|
-
insertBlocks(blocksToInsert, blockToInsertAt, placement, this.tiptapEditor);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Updates a block in the editor to the given specification.
|
|
150
|
-
* @param blockToUpdate The block that should be updated.
|
|
151
|
-
* @param updatedBlock The specification that the block should be updated to.
|
|
152
|
-
*/
|
|
153
|
-
public updateBlock(blockToUpdate: Block, updatedBlock: PartialBlock) {
|
|
154
|
-
updateBlock(blockToUpdate, updatedBlock, this.tiptapEditor);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Removes multiple blocks from the editor. Throws an error if any of the blocks could not be found.
|
|
159
|
-
* @param blocksToRemove An array of blocks that should be removed.
|
|
160
|
-
*/
|
|
161
|
-
public removeBlocks(blocksToRemove: Block[]) {
|
|
162
|
-
removeBlocks(blocksToRemove, this.tiptapEditor);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Replaces multiple blocks in the editor with several other blocks. If the provided blocks to remove are not adjacent
|
|
167
|
-
* to each other, the new blocks are inserted at the position of the first block in the array. Throws an error if any
|
|
168
|
-
* of the blocks could not be found.
|
|
169
|
-
* @param blocksToRemove An array of blocks that should be replaced.
|
|
170
|
-
* @param blocksToInsert An array of blocks to replace the old ones with.
|
|
171
|
-
*/
|
|
172
|
-
public replaceBlocks(
|
|
173
|
-
blocksToRemove: Block[],
|
|
174
|
-
blocksToInsert: PartialBlock[]
|
|
175
|
-
) {
|
|
176
|
-
replaceBlocks(blocksToRemove, blocksToInsert, this.tiptapEditor);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Executes a callback function whenever the editor's contents change.
|
|
181
|
-
* @param callback The callback function to execute.
|
|
182
|
-
*/
|
|
183
|
-
public onContentChange(callback: () => void) {
|
|
184
|
-
this.tiptapEditor.on("update", callback);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Serializes a list of blocks into an HTML string. The output is not the same as what's rendered by the editor, and
|
|
189
|
-
* is simplified in order to better conform to HTML standards. Block structuring elements are removed, children of
|
|
190
|
-
* blocks which aren't list items are lifted out of them, and list items blocks are wrapped in `ul`/`ol` tags.
|
|
191
|
-
* @param blocks The list of blocks to serialize into HTML.
|
|
192
|
-
* @returns An HTML representation of the blocks.
|
|
193
|
-
*/
|
|
194
|
-
public async blocksToHTML(blocks: Block[]): Promise<string> {
|
|
195
|
-
return blocksToHTML(blocks, this.tiptapEditor.schema);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Creates a list of blocks from an HTML string.
|
|
200
|
-
* @param htmlString The HTML string to create a list of blocks from.
|
|
201
|
-
* @returns A list of blocks parsed from the HTML string.
|
|
202
|
-
*/
|
|
203
|
-
public async HTMLToBlocks(htmlString: string): Promise<Block[]> {
|
|
204
|
-
return HTMLToBlocks(htmlString, this.tiptapEditor.schema);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Serializes a list of blocks into a Markdown string. The output is simplified as Markdown does not support all
|
|
209
|
-
* features of BlockNote. Block structuring elements are removed, children of blocks which aren't list items are
|
|
210
|
-
* un-nested, and certain styles are removed.
|
|
211
|
-
* @param blocks The list of blocks to serialize into Markdown.
|
|
212
|
-
* @returns A Markdown representation of the blocks.
|
|
213
|
-
*/
|
|
214
|
-
public async blocksToMarkdown(blocks: Block[]): Promise<string> {
|
|
215
|
-
return blocksToMarkdown(blocks, this.tiptapEditor.schema);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Creates a list of blocks from a Markdown string.
|
|
220
|
-
* @param markdownString The Markdown string to create a list of blocks from.
|
|
221
|
-
* @returns A list of blocks parsed from the Markdown string.
|
|
222
|
-
*/
|
|
223
|
-
public async markdownToBlocks(markdownString: string): Promise<Block[]> {
|
|
224
|
-
return markdownToBlocks(markdownString, this.tiptapEditor.schema);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Editor, Range } from "@tiptap/core";
|
|
2
|
-
import { SuggestionItem } from "../../shared/plugins/suggestion/SuggestionItem";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A class that defines a slash command (/<command>).
|
|
6
|
-
*
|
|
7
|
-
* Not to be confused with ProseMirror commands nor TipTap commands.
|
|
8
|
-
*/
|
|
9
|
-
export class SlashMenuItem implements SuggestionItem {
|
|
10
|
-
/**
|
|
11
|
-
* Constructs a new slash-command.
|
|
12
|
-
*
|
|
13
|
-
* @param name The name of the command
|
|
14
|
-
* @param execute The callback for creating a new node
|
|
15
|
-
* @param aliases Aliases for this command
|
|
16
|
-
*/
|
|
17
|
-
constructor(
|
|
18
|
-
public readonly name: string,
|
|
19
|
-
public readonly execute: (editor: Editor, range: Range) => void,
|
|
20
|
-
public readonly aliases: string[] = [],
|
|
21
|
-
public readonly group: string,
|
|
22
|
-
public readonly hint?: string,
|
|
23
|
-
public readonly shortcut?: string
|
|
24
|
-
) {}
|
|
25
|
-
|
|
26
|
-
match(query: string): boolean {
|
|
27
|
-
return (
|
|
28
|
-
this.name.toLowerCase().startsWith(query.toLowerCase()) ||
|
|
29
|
-
this.aliases.filter((alias) =>
|
|
30
|
-
alias.toLowerCase().startsWith(query.toLowerCase())
|
|
31
|
-
).length !== 0
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
}
|