@blocknote/core 0.1.1 → 0.2.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/README.md +12 -6
- package/dist/blocknote.js +1425 -5114
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +1 -53
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -16
- package/src/BlockNoteEditor.ts +54 -0
- package/src/BlockNoteExtensions.ts +52 -7
- package/src/assets/fonts-inter.css +92 -0
- package/src/editor.module.css +37 -0
- package/src/extensions/Blocks/BlockAttributes.ts +1 -3
- package/src/extensions/Blocks/PreviousBlockTypePlugin.ts +71 -18
- package/src/extensions/Blocks/helpers/getBlockInfoFromPos.ts +66 -0
- package/src/extensions/Blocks/index.ts +7 -3
- package/src/extensions/Blocks/nodes/Block.module.css +116 -74
- package/src/extensions/Blocks/nodes/Block.ts +415 -292
- package/src/extensions/Blocks/nodes/BlockGroup.ts +6 -6
- package/src/extensions/Blocks/nodes/BlockTypes/HeadingBlock/HeadingContent.ts +84 -0
- package/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.ts +177 -0
- package/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.ts +77 -0
- package/src/extensions/Blocks/nodes/BlockTypes/TextBlock/TextContent.ts +34 -0
- package/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.ts +20 -0
- package/src/extensions/DraggableBlocks/DraggableBlocksExtension.ts +27 -9
- package/src/extensions/DraggableBlocks/{DraggableBlocksPlugin.tsx → DraggableBlocksPlugin.ts} +227 -147
- package/src/extensions/FormattingToolbar/FormattingToolbarExtension.ts +29 -0
- package/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.ts +35 -0
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +308 -0
- package/src/extensions/HyperlinkToolbar/HyperlinkMark.ts +28 -0
- package/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.ts +19 -0
- package/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts +251 -0
- package/src/extensions/Placeholder/PlaceholderExtension.ts +2 -2
- package/src/extensions/SlashMenu/SlashMenuExtension.ts +9 -1
- package/src/extensions/SlashMenu/SlashMenuItem.ts +1 -3
- package/src/extensions/SlashMenu/defaultCommands.tsx +33 -22
- package/src/extensions/TrailingNode/TrailingNodeExtension.ts +4 -4
- package/src/extensions/UniqueID/UniqueID.ts +14 -12
- package/src/index.ts +8 -4
- package/src/shared/EditorElement.ts +10 -0
- package/src/shared/plugins/suggestion/SuggestionItem.ts +1 -8
- package/src/shared/plugins/suggestion/SuggestionPlugin.ts +222 -101
- package/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.ts +21 -0
- package/src/{utils.ts → shared/utils.ts} +0 -0
- package/types/src/BlockNoteEditor.d.ts +13 -0
- package/types/src/BlockNoteExtensions.d.ts +12 -1
- package/types/src/EditorElement.d.ts +7 -0
- package/types/src/extensions/Blocks/PreviousBlockTypePlugin.d.ts +1 -1
- package/types/src/extensions/Blocks/helpers/getBlockInfoFromPos.d.ts +19 -0
- package/types/src/extensions/Blocks/nodes/Block.d.ts +11 -19
- package/types/src/extensions/Blocks/nodes/BlockTypes/HeadingBlock/HeadingContent.d.ts +8 -0
- package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.d.ts +8 -0
- package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockTypes/TextBlock/TextContent.d.ts +6 -0
- package/types/src/extensions/BubbleMenu/BubbleMenuExtension.d.ts +4 -1
- package/types/src/extensions/BubbleMenu/BubbleMenuFactoryTypes.d.ts +27 -0
- package/types/src/extensions/BubbleMenu/BubbleMenuPlugin.d.ts +10 -12
- package/types/src/extensions/DraggableBlocks/BlockMenuFactoryTypes.d.ts +12 -0
- package/types/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.d.ts +14 -0
- package/types/src/extensions/DraggableBlocks/DragMenuFactoryTypes.d.ts +18 -0
- package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +9 -3
- package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +23 -1
- package/types/src/extensions/FormattingToolbar/FormattingToolbarExtension.d.ts +8 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +23 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +43 -0
- package/types/src/extensions/HyperlinkToolbar/HyperlinkMark.d.ts +8 -0
- package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.d.ts +12 -0
- package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.d.ts +11 -0
- package/types/src/extensions/Hyperlinks/HyperlinkMark.d.ts +2 -1
- package/types/src/extensions/Hyperlinks/HyperlinkMenuFactoryTypes.d.ts +11 -0
- package/types/src/extensions/Hyperlinks/HyperlinkMenuPlugin.d.ts +10 -1
- package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +3 -1
- package/types/src/extensions/SlashMenu/SlashMenuItem.d.ts +2 -4
- package/types/src/index.d.ts +8 -3
- package/types/src/shared/EditorElement.d.ts +6 -0
- package/types/src/shared/plugins/suggestion/SuggestionItem.d.ts +1 -6
- package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +15 -10
- package/types/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.d.ts +12 -0
- package/types/src/shared/utils.d.ts +2 -0
- package/types/src/utils.d.ts +2 -2
- package/src/BlockNoteTheme.ts +0 -150
- package/src/EditorContent.tsx +0 -2
- package/src/extensions/Blocks/OrderedListPlugin.ts +0 -46
- package/src/extensions/Blocks/commands/joinBackward.ts +0 -274
- package/src/extensions/Blocks/helpers/setBlockHeading.ts +0 -30
- package/src/extensions/Blocks/nodes/Content.ts +0 -63
- package/src/extensions/Blocks/rule.ts +0 -48
- package/src/extensions/BubbleMenu/BubbleMenuExtension.tsx +0 -36
- package/src/extensions/BubbleMenu/BubbleMenuPlugin.ts +0 -245
- package/src/extensions/BubbleMenu/component/BubbleMenu.tsx +0 -240
- package/src/extensions/BubbleMenu/component/LinkToolbarButton.tsx +0 -67
- package/src/extensions/DraggableBlocks/components/DragHandle.tsx +0 -102
- package/src/extensions/DraggableBlocks/components/DragHandleMenu.tsx +0 -19
- package/src/extensions/Hyperlinks/HyperlinkMark.tsx +0 -16
- package/src/extensions/Hyperlinks/HyperlinkMenuPlugin.tsx +0 -165
- package/src/extensions/Hyperlinks/menus/EditHyperlinkMenu.tsx +0 -44
- package/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItem.tsx +0 -34
- package/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemIcon.tsx +0 -31
- package/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemInput.tsx +0 -40
- package/src/extensions/Hyperlinks/menus/HoverHyperlinkMenu.tsx +0 -37
- package/src/extensions/Hyperlinks/menus/HyperlinkMenu.tsx +0 -63
- package/src/fonts-inter.css +0 -94
- package/src/globals.css +0 -28
- package/src/root.module.css +0 -19
- package/src/shared/components/toolbar/Toolbar.tsx +0 -10
- package/src/shared/components/toolbar/ToolbarButton.tsx +0 -57
- package/src/shared/components/toolbar/ToolbarDropdown.tsx +0 -35
- package/src/shared/components/toolbar/ToolbarDropdownItem.tsx +0 -35
- package/src/shared/components/toolbar/ToolbarDropdownTarget.tsx +0 -31
- package/src/shared/components/tooltip/TooltipContent.module.css +0 -15
- package/src/shared/components/tooltip/TooltipContent.tsx +0 -23
- package/src/shared/hooks/useEditorForceUpdate.tsx +0 -30
- package/src/shared/plugins/suggestion/SuggestionListReactRenderer.tsx +0 -236
- package/src/shared/plugins/suggestion/components/SuggestionGroup.tsx +0 -47
- package/src/shared/plugins/suggestion/components/SuggestionGroupItem.tsx +0 -82
- package/src/shared/plugins/suggestion/components/SuggestionList.tsx +0 -92
- package/src/useEditor.ts +0 -51
- package/types/src/BlockNoteTheme.d.ts +0 -2
- package/types/src/EditorContent.d.ts +0 -1
- package/types/src/commands/indentation.d.ts +0 -2
- package/types/src/extensions/Blocks/OrderedListPlugin.d.ts +0 -2
- package/types/src/extensions/Blocks/commands/joinBackward.d.ts +0 -14
- package/types/src/extensions/Blocks/helpers/setBlockHeading.d.ts +0 -5
- package/types/src/extensions/Blocks/nodes/Content.d.ts +0 -5
- package/types/src/extensions/Blocks/rule.d.ts +0 -16
- package/types/src/extensions/BubbleMenu/component/BubbleMenu.d.ts +0 -5
- package/types/src/extensions/BubbleMenu/component/DropdownBlockItem.d.ts +0 -10
- package/types/src/extensions/BubbleMenu/component/LinkToolbarButton.d.ts +0 -11
- package/types/src/extensions/DraggableBlocks/components/DragHandle.d.ts +0 -12
- package/types/src/extensions/DraggableBlocks/components/DragHandleMenu.d.ts +0 -6
- package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenu.d.ts +0 -11
- package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItem.d.ts +0 -13
- package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemIcon.d.ts +0 -8
- package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemInput.d.ts +0 -9
- package/types/src/extensions/Hyperlinks/menus/HoverHyperlinkMenu.d.ts +0 -12
- package/types/src/extensions/Hyperlinks/menus/HyperlinkBasicMenu.d.ts +0 -12
- package/types/src/extensions/Hyperlinks/menus/HyperlinkEditMenu.d.ts +0 -10
- package/types/src/extensions/Hyperlinks/menus/HyperlinkMenu.d.ts +0 -21
- package/types/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInput.d.ts +0 -39
- package/types/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInputStyles.d.ts +0 -1
- package/types/src/extensions/Hyperlinks/menus/atlaskit/ToolbarComponent.d.ts +0 -11
- package/types/src/extensions/Hyperlinks/menus/helpers/PanelTextInput.d.ts +0 -39
- package/types/src/extensions/Hyperlinks/menus/helpers/PanelTextInputStyles.d.ts +0 -3
- package/types/src/extensions/Hyperlinks/menus/helpers/ToolbarComponent.d.ts +0 -13
- package/types/src/extensions/helpers/formatKeyboardShortcut.d.ts +0 -1
- package/types/src/lib/atlaskit/browser.d.ts +0 -12
- package/types/src/nodes/ChildgroupNode.d.ts +0 -28
- package/types/src/nodes/patchNodes.d.ts +0 -1
- package/types/src/plugins/TreeViewPlugin/index.d.ts +0 -2
- package/types/src/plugins/animation.d.ts +0 -2
- package/types/src/react/BlockNoteComposer.d.ts +0 -17
- package/types/src/react/BlockNotePlugin.d.ts +0 -1
- package/types/src/react/index.d.ts +0 -3
- package/types/src/react/useBlockNoteSetup.d.ts +0 -2
- package/types/src/registerBlockNote.d.ts +0 -2
- package/types/src/shared/components/toolbar/SimpleToolbarButton.d.ts +0 -15
- package/types/src/shared/components/toolbar/SimpleToolbarDropdown.d.ts +0 -11
- package/types/src/shared/components/toolbar/SimpleToolbarDropdownItem.d.ts +0 -11
- package/types/src/shared/components/toolbar/Toolbar.d.ts +0 -4
- package/types/src/shared/components/toolbar/ToolbarButton.d.ts +0 -15
- package/types/src/shared/components/toolbar/ToolbarDropdown.d.ts +0 -17
- package/types/src/shared/components/toolbar/ToolbarDropdownItem.d.ts +0 -11
- package/types/src/shared/components/toolbar/ToolbarDropdownTarget.d.ts +0 -8
- package/types/src/shared/components/toolbar/ToolbarSeparator.d.ts +0 -2
- package/types/src/shared/components/tooltip/TooltipContent.d.ts +0 -15
- package/types/src/shared/hooks/useEditorForceUpdate.d.ts +0 -2
- package/types/src/shared/plugins/suggestion/SuggestionListReactRenderer.d.ts +0 -71
- package/types/src/shared/plugins/suggestion/components/SuggestionGroup.d.ts +0 -23
- package/types/src/shared/plugins/suggestion/components/SuggestionGroupItem.d.ts +0 -9
- package/types/src/shared/plugins/suggestion/components/SuggestionList.d.ts +0 -11
- package/types/src/themes/BlockNoteEditorTheme.d.ts +0 -11
- package/types/src/useEditor.d.ts +0 -11
|
@@ -1,41 +1,38 @@
|
|
|
1
1
|
import { mergeAttributes, Node } from "@tiptap/core";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import { OrderedListPlugin } from "../OrderedListPlugin";
|
|
2
|
+
import { Slice } from "prosemirror-model";
|
|
3
|
+
import { TextSelection } from "prosemirror-state";
|
|
4
|
+
import BlockAttributes from "../BlockAttributes";
|
|
5
|
+
import { getBlockInfoFromPos } from "../helpers/getBlockInfoFromPos";
|
|
7
6
|
import { PreviousBlockTypePlugin } from "../PreviousBlockTypePlugin";
|
|
8
|
-
import { textblockTypeInputRuleSameNodeType } from "../rule";
|
|
9
7
|
import styles from "./Block.module.css";
|
|
10
|
-
import
|
|
8
|
+
import { TextContentType } from "./BlockTypes/TextBlock/TextContent";
|
|
9
|
+
import { HeadingContentType } from "./BlockTypes/HeadingBlock/HeadingContent";
|
|
10
|
+
import { ListItemContentType } from "./BlockTypes/ListItemBlock/ListItemContent";
|
|
11
11
|
|
|
12
12
|
export interface IBlock {
|
|
13
13
|
HTMLAttributes: Record<string, any>;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export type
|
|
17
|
-
|
|
16
|
+
export type BlockContentType =
|
|
17
|
+
| TextContentType
|
|
18
|
+
| HeadingContentType
|
|
19
|
+
| ListItemContentType;
|
|
18
20
|
|
|
19
21
|
declare module "@tiptap/core" {
|
|
20
22
|
interface Commands<ReturnType> {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
headingType?: Level;
|
|
35
|
-
listType?: ListType;
|
|
36
|
-
}) => ReturnType;
|
|
37
|
-
|
|
38
|
-
setBlockList: (type: ListType) => ReturnType;
|
|
23
|
+
block: {
|
|
24
|
+
BNCreateBlock: (pos: number) => ReturnType;
|
|
25
|
+
BNDeleteBlock: (posInBlock: number) => ReturnType;
|
|
26
|
+
BNMergeBlocks: (posBetweenBlocks: number) => ReturnType;
|
|
27
|
+
BNSplitBlock: (posInBlock: number, keepType: boolean) => ReturnType;
|
|
28
|
+
BNSetContentType: (
|
|
29
|
+
posInBlock: number,
|
|
30
|
+
type: BlockContentType
|
|
31
|
+
) => ReturnType;
|
|
32
|
+
BNCreateBlockOrSetContentType: (
|
|
33
|
+
posInBlock: number,
|
|
34
|
+
type: BlockContentType
|
|
35
|
+
) => ReturnType;
|
|
39
36
|
};
|
|
40
37
|
}
|
|
41
38
|
}
|
|
@@ -46,38 +43,31 @@ declare module "@tiptap/core" {
|
|
|
46
43
|
export const Block = Node.create<IBlock>({
|
|
47
44
|
name: "block",
|
|
48
45
|
group: "block",
|
|
46
|
+
// A block always contains content, and optionally a blockGroup which contains nested blocks
|
|
47
|
+
content: "blockContent blockGroup?",
|
|
48
|
+
// Ensures content-specific keyboard handlers trigger first.
|
|
49
|
+
priority: 50,
|
|
50
|
+
defining: true,
|
|
51
|
+
|
|
49
52
|
addOptions() {
|
|
50
53
|
return {
|
|
51
54
|
HTMLAttributes: {},
|
|
52
55
|
};
|
|
53
56
|
},
|
|
54
57
|
|
|
55
|
-
// A block always contains content, and optionally a blockGroup which contains nested blocks
|
|
56
|
-
content: "content blockgroup?",
|
|
57
|
-
|
|
58
|
-
defining: true,
|
|
59
|
-
|
|
60
58
|
addAttributes() {
|
|
61
59
|
return {
|
|
62
|
-
listType: {
|
|
63
|
-
default: undefined,
|
|
64
|
-
},
|
|
65
60
|
blockColor: {
|
|
66
61
|
default: undefined,
|
|
67
62
|
},
|
|
68
63
|
blockStyle: {
|
|
69
64
|
default: undefined,
|
|
70
65
|
},
|
|
71
|
-
headingType: {
|
|
72
|
-
default: undefined,
|
|
73
|
-
keepOnSplit: false,
|
|
74
|
-
},
|
|
75
66
|
};
|
|
76
67
|
},
|
|
77
68
|
|
|
78
69
|
parseHTML() {
|
|
79
70
|
return [
|
|
80
|
-
// For parsing blocks within the editor.
|
|
81
71
|
{
|
|
82
72
|
tag: "div",
|
|
83
73
|
getAttrs: (element) => {
|
|
@@ -96,49 +86,6 @@ export const Block = Node.create<IBlock>({
|
|
|
96
86
|
return attrs;
|
|
97
87
|
}
|
|
98
88
|
|
|
99
|
-
return false;
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
// For parsing headings & paragraphs copied from outside the editor.
|
|
103
|
-
{
|
|
104
|
-
tag: "p",
|
|
105
|
-
priority: 100,
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
tag: "h1",
|
|
109
|
-
attrs: { headingType: "1" },
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
tag: "h2",
|
|
113
|
-
attrs: { headingType: "2" },
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
tag: "h3",
|
|
117
|
-
attrs: { headingType: "3" },
|
|
118
|
-
},
|
|
119
|
-
// For parsing list items copied from outside the editor.
|
|
120
|
-
{
|
|
121
|
-
tag: "li",
|
|
122
|
-
getAttrs: (element) => {
|
|
123
|
-
if (typeof element === "string") {
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const parent = element.parentElement;
|
|
128
|
-
|
|
129
|
-
if (parent === null) {
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Gets type of list item (ordered/unordered) based on parent element's tag ("ol"/"ul").
|
|
134
|
-
if (parent.tagName === "UL") {
|
|
135
|
-
return { listType: "li" };
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (parent.tagName === "OL") {
|
|
139
|
-
return { listType: "oli" };
|
|
140
|
-
}
|
|
141
|
-
|
|
142
89
|
return false;
|
|
143
90
|
},
|
|
144
91
|
},
|
|
@@ -148,7 +95,10 @@ export const Block = Node.create<IBlock>({
|
|
|
148
95
|
renderHTML({ HTMLAttributes }) {
|
|
149
96
|
const attrs: Record<string, string> = {};
|
|
150
97
|
for (let [nodeAttr, HTMLAttr] of Object.entries(BlockAttributes)) {
|
|
151
|
-
|
|
98
|
+
// Ensure falsy values are not misinterpreted.
|
|
99
|
+
if (HTMLAttributes[nodeAttr] !== undefined) {
|
|
100
|
+
attrs[HTMLAttr] = HTMLAttributes[nodeAttr];
|
|
101
|
+
}
|
|
152
102
|
}
|
|
153
103
|
|
|
154
104
|
return [
|
|
@@ -160,275 +110,448 @@ export const Block = Node.create<IBlock>({
|
|
|
160
110
|
[
|
|
161
111
|
"div",
|
|
162
112
|
mergeAttributes(attrs, {
|
|
113
|
+
// TODO: maybe remove html attributes from inner block
|
|
163
114
|
class: styles.block,
|
|
164
|
-
"data-node-type":
|
|
115
|
+
"data-node-type": this.name,
|
|
165
116
|
}),
|
|
166
117
|
0,
|
|
167
118
|
],
|
|
168
119
|
];
|
|
169
120
|
},
|
|
170
121
|
|
|
171
|
-
addInputRules() {
|
|
172
|
-
return [
|
|
173
|
-
...["1", "2", "3"].map((level) => {
|
|
174
|
-
// Create a heading when starting with "#", "##", or "###""
|
|
175
|
-
return textblockTypeInputRuleSameNodeType({
|
|
176
|
-
find: new RegExp(`^(#{1,${level}})\\s$`),
|
|
177
|
-
type: this.type,
|
|
178
|
-
getAttributes: {
|
|
179
|
-
headingType: level,
|
|
180
|
-
},
|
|
181
|
-
});
|
|
182
|
-
}),
|
|
183
|
-
// Create a list when starting with "-"
|
|
184
|
-
textblockTypeInputRuleSameNodeType({
|
|
185
|
-
find: /^\s*([-+*])\s$/,
|
|
186
|
-
type: this.type,
|
|
187
|
-
getAttributes: {
|
|
188
|
-
listType: "li",
|
|
189
|
-
},
|
|
190
|
-
}),
|
|
191
|
-
textblockTypeInputRuleSameNodeType({
|
|
192
|
-
find: new RegExp(/^1.\s/),
|
|
193
|
-
type: this.type,
|
|
194
|
-
getAttributes: {
|
|
195
|
-
listType: "oli",
|
|
196
|
-
},
|
|
197
|
-
}),
|
|
198
|
-
];
|
|
199
|
-
},
|
|
200
|
-
|
|
201
122
|
addCommands() {
|
|
202
123
|
return {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
(
|
|
206
|
-
|
|
124
|
+
// Creates a new text block at a given position.
|
|
125
|
+
BNCreateBlock:
|
|
126
|
+
(pos) =>
|
|
127
|
+
({ state, dispatch }) => {
|
|
128
|
+
const newBlock = state.schema.nodes["block"].createAndFill()!;
|
|
129
|
+
|
|
130
|
+
if (dispatch) {
|
|
131
|
+
state.tr.insert(pos, newBlock);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return true;
|
|
207
135
|
},
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
(
|
|
211
|
-
|
|
136
|
+
// Deletes a block at a given position and sets the selection to where the block was.
|
|
137
|
+
BNDeleteBlock:
|
|
138
|
+
(posInBlock) =>
|
|
139
|
+
({ state, view, dispatch }) => {
|
|
140
|
+
const blockInfo = getBlockInfoFromPos(state.doc, posInBlock);
|
|
141
|
+
if (blockInfo === undefined) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const { startPos, endPos } = blockInfo;
|
|
146
|
+
|
|
147
|
+
if (dispatch) {
|
|
148
|
+
state.tr.deleteRange(startPos, endPos);
|
|
149
|
+
state.tr.setSelection(
|
|
150
|
+
new TextSelection(state.doc.resolve(startPos + 1))
|
|
151
|
+
);
|
|
152
|
+
view.focus();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return true;
|
|
212
156
|
},
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
157
|
+
// Appends the text contents of a block to the nearest previous block, given a position between them. Children of
|
|
158
|
+
// the merged block are moved out of it first, rather than also being merged.
|
|
159
|
+
//
|
|
160
|
+
// In the example below, the position passed into the function is between Block1 and Block2.
|
|
161
|
+
//
|
|
162
|
+
// Block1
|
|
163
|
+
// Block2
|
|
164
|
+
// Block3
|
|
165
|
+
// Block4
|
|
166
|
+
// Block5
|
|
167
|
+
//
|
|
168
|
+
// Becomes:
|
|
169
|
+
//
|
|
170
|
+
// Block1
|
|
171
|
+
// Block2Block3
|
|
172
|
+
// Block4
|
|
173
|
+
// Block5
|
|
174
|
+
BNMergeBlocks:
|
|
175
|
+
(posBetweenBlocks) =>
|
|
176
|
+
({ state, dispatch }) => {
|
|
177
|
+
const nextNodeIsBlock =
|
|
178
|
+
state.doc.resolve(posBetweenBlocks + 1).node().type.name ===
|
|
179
|
+
"block";
|
|
180
|
+
const prevNodeIsBlock =
|
|
181
|
+
state.doc.resolve(posBetweenBlocks - 1).node().type.name ===
|
|
182
|
+
"block";
|
|
183
|
+
|
|
184
|
+
if (!nextNodeIsBlock || !prevNodeIsBlock) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const nextBlockInfo = getBlockInfoFromPos(
|
|
189
|
+
state.doc,
|
|
190
|
+
posBetweenBlocks + 1
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const { node, contentNode, startPos, endPos, depth } = nextBlockInfo!;
|
|
194
|
+
|
|
195
|
+
// Removes a level of nesting all children of the next block by 1 level, if it contains both content and block
|
|
196
|
+
// group nodes.
|
|
197
|
+
if (node.childCount === 2) {
|
|
198
|
+
const childBlocksStart = state.doc.resolve(
|
|
199
|
+
startPos + contentNode.nodeSize + 1
|
|
200
|
+
);
|
|
201
|
+
const childBlocksEnd = state.doc.resolve(endPos - 1);
|
|
202
|
+
const childBlocksRange =
|
|
203
|
+
childBlocksStart.blockRange(childBlocksEnd);
|
|
218
204
|
|
|
219
|
-
|
|
220
|
-
if (node.type.name === "block" && node.attrs["listType"]) {
|
|
205
|
+
// Moves the block group node inside the block into the block group node that the current block is in.
|
|
221
206
|
if (dispatch) {
|
|
222
|
-
tr.
|
|
223
|
-
...node.attrs,
|
|
224
|
-
listType: undefined,
|
|
225
|
-
});
|
|
226
|
-
return true;
|
|
207
|
+
state.tr.lift(childBlocksRange!, depth - 1);
|
|
227
208
|
}
|
|
228
209
|
}
|
|
229
|
-
return false;
|
|
230
|
-
},
|
|
231
210
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
//
|
|
236
|
-
|
|
237
|
-
|
|
211
|
+
let prevBlockEndPos = posBetweenBlocks - 1;
|
|
212
|
+
let prevBlockInfo = getBlockInfoFromPos(state.doc, prevBlockEndPos);
|
|
213
|
+
|
|
214
|
+
// Finds the nearest previous block, regardless of nesting level.
|
|
215
|
+
while (prevBlockInfo!.numChildBlocks > 0) {
|
|
216
|
+
prevBlockEndPos--;
|
|
217
|
+
prevBlockInfo = getBlockInfoFromPos(state.doc, prevBlockEndPos);
|
|
218
|
+
if (prevBlockInfo === undefined) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Deletes next block and adds its text content to the nearest previous block.
|
|
224
|
+
// TODO: Is there any situation where we need the whole block content, not just text? Implementation for this
|
|
225
|
+
// is trickier.
|
|
226
|
+
if (dispatch) {
|
|
227
|
+
state.tr.deleteRange(startPos, startPos + contentNode.nodeSize);
|
|
228
|
+
state.tr.insertText(contentNode.textContent, prevBlockEndPos - 1);
|
|
229
|
+
state.tr.setSelection(
|
|
230
|
+
new TextSelection(state.doc.resolve(prevBlockEndPos - 1))
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return true;
|
|
235
|
+
},
|
|
236
|
+
// Splits a block at a given position. Content after the position is moved to a new block below, at the same
|
|
237
|
+
// nesting level.
|
|
238
|
+
BNSplitBlock:
|
|
239
|
+
(posInBlock, keepType) =>
|
|
240
|
+
({ state, dispatch }) => {
|
|
241
|
+
const blockInfo = getBlockInfoFromPos(state.doc, posInBlock);
|
|
242
|
+
if (blockInfo === undefined) {
|
|
238
243
|
return false;
|
|
239
244
|
}
|
|
240
245
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
246
|
+
const { contentNode, contentType, startPos, endPos, depth } =
|
|
247
|
+
blockInfo;
|
|
248
|
+
|
|
249
|
+
const newBlockInsertionPos = endPos + 1;
|
|
250
|
+
|
|
251
|
+
// Creates new block first, otherwise positions get changed due to the original block's content changing.
|
|
252
|
+
// Only text content is transferred to the new block.
|
|
253
|
+
const secondBlockContent = state.doc.textBetween(posInBlock, endPos);
|
|
254
|
+
|
|
255
|
+
const newBlock = state.schema.nodes["block"].createAndFill()!;
|
|
256
|
+
const newBlockContentPos = newBlockInsertionPos + 2;
|
|
257
|
+
|
|
258
|
+
if (dispatch) {
|
|
259
|
+
state.tr.insert(newBlockInsertionPos, newBlock);
|
|
260
|
+
state.tr.insertText(secondBlockContent, newBlockContentPos);
|
|
261
|
+
|
|
262
|
+
if (keepType) {
|
|
263
|
+
state.tr.setBlockType(
|
|
264
|
+
newBlockContentPos,
|
|
265
|
+
newBlockContentPos,
|
|
266
|
+
state.schema.node(contentType).type,
|
|
267
|
+
contentNode.attrs
|
|
268
|
+
);
|
|
245
269
|
}
|
|
246
|
-
return true;
|
|
247
270
|
}
|
|
248
271
|
|
|
249
|
-
//
|
|
250
|
-
const
|
|
251
|
-
|
|
272
|
+
// Updates content of original block.
|
|
273
|
+
const firstBlockContent = state.doc.content.cut(startPos, posInBlock);
|
|
274
|
+
|
|
252
275
|
if (dispatch) {
|
|
253
|
-
tr.
|
|
254
|
-
|
|
276
|
+
state.tr.replace(
|
|
277
|
+
startPos,
|
|
278
|
+
endPos,
|
|
279
|
+
new Slice(firstBlockContent, depth, depth)
|
|
280
|
+
);
|
|
255
281
|
}
|
|
282
|
+
|
|
256
283
|
return true;
|
|
257
284
|
},
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
(
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
285
|
+
// Changes the content of a block at a given position to a given type.
|
|
286
|
+
BNSetContentType:
|
|
287
|
+
(posInBlock, type) =>
|
|
288
|
+
({ state, dispatch }) => {
|
|
289
|
+
const blockInfo = getBlockInfoFromPos(state.doc, posInBlock);
|
|
290
|
+
if (blockInfo === undefined) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const { startPos, contentNode } = blockInfo;
|
|
295
|
+
|
|
296
|
+
if (dispatch) {
|
|
297
|
+
state.tr.setBlockType(
|
|
298
|
+
startPos + 1,
|
|
299
|
+
startPos + contentNode.nodeSize + 1,
|
|
300
|
+
state.schema.node(type.name).type,
|
|
301
|
+
type.attrs
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return true;
|
|
306
|
+
},
|
|
307
|
+
// Changes the block at a given position to a given content type if it's empty, otherwise creates a new block of
|
|
308
|
+
// that type below it.
|
|
309
|
+
BNCreateBlockOrSetContentType:
|
|
310
|
+
(posInBlock, type) =>
|
|
311
|
+
({ state, chain }) => {
|
|
312
|
+
const blockInfo = getBlockInfoFromPos(state.doc, posInBlock);
|
|
313
|
+
if (blockInfo === undefined) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const { node, startPos, endPos } = blockInfo;
|
|
318
|
+
|
|
319
|
+
if (node.textContent.length === 0) {
|
|
320
|
+
const oldBlockContentPos = startPos + 1;
|
|
321
|
+
|
|
322
|
+
return chain()
|
|
323
|
+
.BNSetContentType(posInBlock, type)
|
|
324
|
+
.setTextSelection(oldBlockContentPos)
|
|
325
|
+
.run();
|
|
326
|
+
} else {
|
|
327
|
+
const newBlockInsertionPos = endPos + 1;
|
|
328
|
+
const newBlockContentPos = newBlockInsertionPos + 1;
|
|
329
|
+
|
|
330
|
+
return chain()
|
|
331
|
+
.BNCreateBlock(newBlockInsertionPos)
|
|
332
|
+
.BNSetContentType(newBlockContentPos, type)
|
|
333
|
+
.setTextSelection(newBlockContentPos)
|
|
334
|
+
.run();
|
|
273
335
|
}
|
|
274
|
-
return false;
|
|
275
336
|
},
|
|
276
|
-
joinBackward:
|
|
277
|
-
() =>
|
|
278
|
-
({ view, dispatch, state }) =>
|
|
279
|
-
joinBackward(state, dispatch, view), // Override default joinBackward with edited command
|
|
280
337
|
};
|
|
281
338
|
},
|
|
339
|
+
|
|
282
340
|
addProseMirrorPlugins() {
|
|
283
|
-
return [PreviousBlockTypePlugin()
|
|
341
|
+
return [PreviousBlockTypePlugin()];
|
|
284
342
|
},
|
|
343
|
+
|
|
285
344
|
addKeyboardShortcuts() {
|
|
286
345
|
// handleBackspace is partially adapted from https://github.com/ueberdosis/tiptap/blob/ed56337470efb4fd277128ab7ef792b37cfae992/packages/core/src/extensions/keymap.ts
|
|
287
346
|
const handleBackspace = () =>
|
|
288
347
|
this.editor.commands.first(({ commands }) => [
|
|
289
|
-
//
|
|
348
|
+
// Deletes the selection if it's not empty.
|
|
349
|
+
() => commands.deleteSelection(),
|
|
350
|
+
// Undoes an input rule if one was triggered in the last editor state change.
|
|
290
351
|
() => commands.undoInputRule(),
|
|
291
|
-
//
|
|
352
|
+
// Changes block type to a text block if it's not already, while the selection is at the start of the block.
|
|
353
|
+
() =>
|
|
354
|
+
commands.command(({ state }) => {
|
|
355
|
+
const { contentType } = getBlockInfoFromPos(
|
|
356
|
+
state.doc,
|
|
357
|
+
state.selection.from
|
|
358
|
+
)!;
|
|
359
|
+
|
|
360
|
+
const selectionAtBlockStart =
|
|
361
|
+
state.selection.$anchor.parentOffset === 0;
|
|
362
|
+
const isTextBlock = contentType.name === "textContent";
|
|
363
|
+
|
|
364
|
+
if (selectionAtBlockStart && !isTextBlock) {
|
|
365
|
+
return commands.BNSetContentType(state.selection.from, {
|
|
366
|
+
name: "textContent",
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return false;
|
|
371
|
+
}),
|
|
372
|
+
// Removes a level of nesting if the block is indented if the selection is at the start of the block.
|
|
292
373
|
() =>
|
|
293
|
-
commands.command(({
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
const { pos, parent } = $anchor;
|
|
297
|
-
const isAtStart = Selection.atStart(doc).from === pos;
|
|
374
|
+
commands.command(({ state }) => {
|
|
375
|
+
const selectionAtBlockStart =
|
|
376
|
+
state.selection.$anchor.parentOffset === 0;
|
|
298
377
|
|
|
299
|
-
if (
|
|
300
|
-
|
|
301
|
-
!isAtStart ||
|
|
302
|
-
!parent.type.isTextblock ||
|
|
303
|
-
parent.textContent.length
|
|
304
|
-
) {
|
|
305
|
-
return false;
|
|
378
|
+
if (selectionAtBlockStart) {
|
|
379
|
+
return commands.liftListItem("block");
|
|
306
380
|
}
|
|
307
381
|
|
|
308
|
-
return
|
|
382
|
+
return false;
|
|
309
383
|
}),
|
|
310
|
-
|
|
384
|
+
// Merges block with the previous one if it isn't indented, isn't the first block in the doc, and the selection
|
|
385
|
+
// is at the start of the block.
|
|
311
386
|
() =>
|
|
312
|
-
commands.command(({
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
387
|
+
commands.command(({ state }) => {
|
|
388
|
+
const { depth, startPos } = getBlockInfoFromPos(
|
|
389
|
+
state.doc,
|
|
390
|
+
state.selection.from
|
|
391
|
+
)!;
|
|
392
|
+
|
|
393
|
+
const selectionAtBlockStart =
|
|
394
|
+
state.selection.$anchor.parentOffset === 0;
|
|
395
|
+
const selectionEmpty =
|
|
396
|
+
state.selection.anchor === state.selection.head;
|
|
397
|
+
const blockAtDocStart = startPos === 2;
|
|
398
|
+
|
|
399
|
+
const posBetweenBlocks = startPos - 1;
|
|
400
|
+
|
|
401
|
+
if (
|
|
402
|
+
!blockAtDocStart &&
|
|
403
|
+
selectionAtBlockStart &&
|
|
404
|
+
selectionEmpty &&
|
|
405
|
+
depth === 2
|
|
406
|
+
) {
|
|
407
|
+
return commands.BNMergeBlocks(posBetweenBlocks);
|
|
321
408
|
}
|
|
409
|
+
|
|
322
410
|
return false;
|
|
323
411
|
}),
|
|
324
|
-
({ chain }) =>
|
|
325
|
-
// we are at the start of a block at the root level. The user hits backspace to "merge it" to the end of the block above
|
|
326
|
-
//
|
|
327
|
-
// BlockA
|
|
328
|
-
// BlockB
|
|
329
|
-
|
|
330
|
-
// Becomes:
|
|
331
|
-
|
|
332
|
-
// BlockABlockB
|
|
333
|
-
|
|
334
|
-
chain()
|
|
335
|
-
.command(({ tr, state, dispatch }) => {
|
|
336
|
-
const isAtStartOfNode = tr.selection.$anchor.parentOffset === 0;
|
|
337
|
-
const anchor = tr.selection.$anchor;
|
|
338
|
-
const node = anchor.node(-1);
|
|
339
|
-
if (isAtStartOfNode && node.type.name === "block") {
|
|
340
|
-
if (node.childCount === 2) {
|
|
341
|
-
// BlockB has children. We want to go from this:
|
|
342
|
-
//
|
|
343
|
-
// BlockA
|
|
344
|
-
// BlockB
|
|
345
|
-
// BlockC
|
|
346
|
-
// BlockD
|
|
347
|
-
//
|
|
348
|
-
// to:
|
|
349
|
-
//
|
|
350
|
-
// BlockABlockB
|
|
351
|
-
// BlockC
|
|
352
|
-
// BlockD
|
|
353
|
-
|
|
354
|
-
// This parts moves the children of BlockB to the top level
|
|
355
|
-
const startSecondChild = anchor.posAtIndex(1, -1) + 1; // start of blockgroup
|
|
356
|
-
const endSecondChild = anchor.posAtIndex(2, -1) - 1;
|
|
357
|
-
const range = state.doc
|
|
358
|
-
.resolve(startSecondChild)
|
|
359
|
-
.blockRange(state.doc.resolve(endSecondChild));
|
|
360
|
-
|
|
361
|
-
if (dispatch) {
|
|
362
|
-
tr.lift(range!, anchor.depth - 2);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
return true;
|
|
366
|
-
}
|
|
367
|
-
return false;
|
|
368
|
-
})
|
|
369
|
-
// use joinBackward to merge BlockB to BlockA (i.e.: turn it into BlockABlockB)
|
|
370
|
-
// The standard JoinBackward would break here, and would turn it into:
|
|
371
|
-
// BlockA
|
|
372
|
-
// BlockB
|
|
373
|
-
//
|
|
374
|
-
// joinBackward has been patched with our custom version to fix this (see commands/joinBackward)
|
|
375
|
-
.joinBackward()
|
|
376
|
-
.run(),
|
|
377
|
-
|
|
378
|
-
() => commands.selectNodeBackward(), // (source: tiptap)
|
|
379
412
|
]);
|
|
380
413
|
|
|
381
414
|
const handleEnter = () =>
|
|
382
415
|
this.editor.commands.first(({ commands }) => [
|
|
383
|
-
//
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
416
|
+
// Removes a level of nesting if the block is empty & indented, while the selection is also empty & at the start
|
|
417
|
+
// of the block.
|
|
418
|
+
() =>
|
|
419
|
+
commands.command(({ state }) => {
|
|
420
|
+
const { node, depth } = getBlockInfoFromPos(
|
|
421
|
+
state.doc,
|
|
422
|
+
state.selection.from
|
|
423
|
+
)!;
|
|
424
|
+
|
|
425
|
+
const selectionAtBlockStart =
|
|
426
|
+
state.selection.$anchor.parentOffset === 0;
|
|
427
|
+
const selectionEmpty =
|
|
428
|
+
state.selection.anchor === state.selection.head;
|
|
429
|
+
const blockEmpty = node.textContent.length === 0;
|
|
430
|
+
const blockIndented = depth > 2;
|
|
431
|
+
|
|
432
|
+
if (
|
|
433
|
+
selectionAtBlockStart &&
|
|
434
|
+
selectionEmpty &&
|
|
435
|
+
blockEmpty &&
|
|
436
|
+
blockIndented
|
|
437
|
+
) {
|
|
438
|
+
return commands.liftListItem("block");
|
|
439
|
+
}
|
|
440
|
+
|
|
390
441
|
return false;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
442
|
+
}),
|
|
443
|
+
// Creates a new block and moves the selection to it if the current one is empty, while the selection is also
|
|
444
|
+
// empty & at the start of the block.
|
|
445
|
+
() =>
|
|
446
|
+
commands.command(({ state, chain }) => {
|
|
447
|
+
const { node, endPos } = getBlockInfoFromPos(
|
|
448
|
+
state.doc,
|
|
449
|
+
state.selection.from
|
|
450
|
+
)!;
|
|
451
|
+
|
|
452
|
+
const selectionAtBlockStart =
|
|
453
|
+
state.selection.$anchor.parentOffset === 0;
|
|
454
|
+
const selectionEmpty =
|
|
455
|
+
state.selection.anchor === state.selection.head;
|
|
456
|
+
const blockEmpty = node.textContent.length === 0;
|
|
457
|
+
|
|
458
|
+
if (selectionAtBlockStart && selectionEmpty && blockEmpty) {
|
|
459
|
+
const newBlockInsertionPos = endPos + 1;
|
|
460
|
+
const newBlockContentPos = newBlockInsertionPos + 2;
|
|
461
|
+
|
|
462
|
+
chain()
|
|
463
|
+
.BNCreateBlock(newBlockInsertionPos)
|
|
464
|
+
.setTextSelection(newBlockContentPos)
|
|
465
|
+
.run();
|
|
394
466
|
|
|
395
|
-
|
|
396
|
-
if (dispatch) {
|
|
397
|
-
tr.setNodeMarkup(nodePos, undefined, {
|
|
398
|
-
...node.attrs,
|
|
399
|
-
listType: undefined,
|
|
400
|
-
});
|
|
467
|
+
return true;
|
|
401
468
|
}
|
|
402
|
-
return true;
|
|
403
|
-
}
|
|
404
|
-
return false;
|
|
405
|
-
},
|
|
406
|
-
// Otherwise, we might be on an empty line and hit "Enter" to create a new line:
|
|
407
|
-
({ tr, dispatch }) => {
|
|
408
|
-
const $from = tr.selection.$from;
|
|
409
469
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
470
|
+
return false;
|
|
471
|
+
}),
|
|
472
|
+
// Splits the current block, moving content inside that's after the cursor to a new text block below. Also
|
|
473
|
+
// deletes the selection beforehand, if it's not empty.
|
|
474
|
+
() =>
|
|
475
|
+
commands.command(({ state, chain }) => {
|
|
476
|
+
const { node } = getBlockInfoFromPos(
|
|
477
|
+
state.doc,
|
|
478
|
+
state.selection.from
|
|
479
|
+
)!;
|
|
480
|
+
|
|
481
|
+
const blockEmpty = node.textContent.length === 0;
|
|
482
|
+
|
|
483
|
+
if (!blockEmpty) {
|
|
484
|
+
chain()
|
|
485
|
+
.deleteSelection()
|
|
486
|
+
.BNSplitBlock(state.selection.from, false)
|
|
487
|
+
.run();
|
|
488
|
+
|
|
489
|
+
return true;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
return false;
|
|
493
|
+
}),
|
|
415
494
|
]);
|
|
416
495
|
|
|
417
496
|
return {
|
|
418
497
|
Backspace: handleBackspace,
|
|
419
498
|
Enter: handleEnter,
|
|
420
499
|
Tab: () => this.editor.commands.sinkListItem("block"),
|
|
421
|
-
"Shift-Tab": () =>
|
|
422
|
-
return this.editor.commands.liftListItem("block");
|
|
423
|
-
},
|
|
500
|
+
"Shift-Tab": () => this.editor.commands.liftListItem("block"),
|
|
424
501
|
"Mod-Alt-0": () =>
|
|
425
|
-
this.editor.
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
"Mod-Alt-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
502
|
+
this.editor.commands.BNCreateBlock(
|
|
503
|
+
this.editor.state.selection.anchor + 2
|
|
504
|
+
),
|
|
505
|
+
"Mod-Alt-1": () =>
|
|
506
|
+
this.editor.commands.BNSetContentType(
|
|
507
|
+
this.editor.state.selection.anchor,
|
|
508
|
+
{
|
|
509
|
+
name: "headingContent",
|
|
510
|
+
attrs: {
|
|
511
|
+
headingLevel: "1",
|
|
512
|
+
},
|
|
513
|
+
}
|
|
514
|
+
),
|
|
515
|
+
"Mod-Alt-2": () =>
|
|
516
|
+
this.editor.commands.BNSetContentType(
|
|
517
|
+
this.editor.state.selection.anchor,
|
|
518
|
+
{
|
|
519
|
+
name: "headingContent",
|
|
520
|
+
attrs: {
|
|
521
|
+
headingLevel: "2",
|
|
522
|
+
},
|
|
523
|
+
}
|
|
524
|
+
),
|
|
525
|
+
"Mod-Alt-3": () =>
|
|
526
|
+
this.editor.commands.BNSetContentType(
|
|
527
|
+
this.editor.state.selection.anchor,
|
|
528
|
+
{
|
|
529
|
+
name: "headingContent",
|
|
530
|
+
attrs: {
|
|
531
|
+
headingLevel: "3",
|
|
532
|
+
},
|
|
533
|
+
}
|
|
534
|
+
),
|
|
535
|
+
"Mod-Shift-7": () =>
|
|
536
|
+
this.editor.commands.BNSetContentType(
|
|
537
|
+
this.editor.state.selection.anchor,
|
|
538
|
+
{
|
|
539
|
+
name: "listItemContent",
|
|
540
|
+
attrs: {
|
|
541
|
+
listItemType: "unordered",
|
|
542
|
+
},
|
|
543
|
+
}
|
|
544
|
+
),
|
|
545
|
+
"Mod-Shift-8": () =>
|
|
546
|
+
this.editor.commands.BNSetContentType(
|
|
547
|
+
this.editor.state.selection.anchor,
|
|
548
|
+
{
|
|
549
|
+
name: "listItemContent",
|
|
550
|
+
attrs: {
|
|
551
|
+
listItemType: "ordered",
|
|
552
|
+
},
|
|
553
|
+
}
|
|
554
|
+
),
|
|
432
555
|
};
|
|
433
556
|
},
|
|
434
557
|
});
|