@blocknote/core 0.1.2 → 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 +1424 -5109
- 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 +413 -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 -1
- 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
package/src/BlockNoteTheme.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { MantineThemeOverride } from "@mantine/core";
|
|
2
|
-
|
|
3
|
-
export const BlockNoteTheme: MantineThemeOverride = {
|
|
4
|
-
activeStyles: {
|
|
5
|
-
// Removes button press effect.
|
|
6
|
-
transform: "none",
|
|
7
|
-
},
|
|
8
|
-
colorScheme: "light",
|
|
9
|
-
colors: {
|
|
10
|
-
brandFinal: [
|
|
11
|
-
"#F6F6F8",
|
|
12
|
-
"#ECEDF0",
|
|
13
|
-
"#DFE1E6",
|
|
14
|
-
"#C2C7D0",
|
|
15
|
-
"#A6ADBA",
|
|
16
|
-
"#8993A4",
|
|
17
|
-
"#6D798F",
|
|
18
|
-
"#505F79",
|
|
19
|
-
"#344563",
|
|
20
|
-
"#172B4D",
|
|
21
|
-
],
|
|
22
|
-
},
|
|
23
|
-
components: {
|
|
24
|
-
Menu: {
|
|
25
|
-
styles: (theme) => ({
|
|
26
|
-
dropdown: {
|
|
27
|
-
backgroundColor: "white",
|
|
28
|
-
boxShadow: `0px 4px 8px ${theme.colors.brandFinal[2]}, 0px 0px 1px ${theme.colors.brandFinal[2]}`,
|
|
29
|
-
border: `1px solid ${theme.colors.brandFinal[1]}`,
|
|
30
|
-
borderRadius: "6px",
|
|
31
|
-
padding: "2px",
|
|
32
|
-
},
|
|
33
|
-
}),
|
|
34
|
-
},
|
|
35
|
-
DragHandleMenu: {
|
|
36
|
-
styles: (theme) => ({
|
|
37
|
-
root: {
|
|
38
|
-
".mantine-Menu-item": {
|
|
39
|
-
color: theme.colors.brandFinal,
|
|
40
|
-
fontSize: "12px",
|
|
41
|
-
height: "34px",
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
}),
|
|
45
|
-
},
|
|
46
|
-
EditHyperlinkMenu: {
|
|
47
|
-
styles: (theme) => ({
|
|
48
|
-
root: {
|
|
49
|
-
backgroundColor: "white",
|
|
50
|
-
boxShadow: `0px 4px 8px ${theme.colors.brandFinal[2]}, 0px 0px 1px ${theme.colors.brandFinal[2]}`,
|
|
51
|
-
border: `1px solid ${theme.colors.brandFinal[1]}`,
|
|
52
|
-
borderRadius: "6px",
|
|
53
|
-
gap: "4px",
|
|
54
|
-
minWidth: "145px",
|
|
55
|
-
padding: "2px",
|
|
56
|
-
// Row
|
|
57
|
-
".mantine-Group-root": {
|
|
58
|
-
flexWrap: "nowrap",
|
|
59
|
-
gap: "8px",
|
|
60
|
-
paddingInline: "6px",
|
|
61
|
-
// Row icon
|
|
62
|
-
".mantine-Container-root": {
|
|
63
|
-
color: theme.colors.brandFinal,
|
|
64
|
-
display: "flex",
|
|
65
|
-
justifyContent: "center",
|
|
66
|
-
padding: "0",
|
|
67
|
-
width: "fit-content",
|
|
68
|
-
},
|
|
69
|
-
// Row input field
|
|
70
|
-
".mantine-TextInput-root": {
|
|
71
|
-
background: "transparent",
|
|
72
|
-
width: "300px",
|
|
73
|
-
".mantine-TextInput-wrapper": {
|
|
74
|
-
".mantine-TextInput-input": {
|
|
75
|
-
fontSize: "12px",
|
|
76
|
-
border: 0,
|
|
77
|
-
padding: 0,
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
}),
|
|
84
|
-
},
|
|
85
|
-
Toolbar: {
|
|
86
|
-
styles: (theme) => ({
|
|
87
|
-
root: {
|
|
88
|
-
backgroundColor: "white",
|
|
89
|
-
boxShadow: `0px 4px 8px ${theme.colors.brandFinal[2]}, 0px 0px 1px ${theme.colors.brandFinal[2]}`,
|
|
90
|
-
border: `1px solid ${theme.colors.brandFinal[1]}`,
|
|
91
|
-
borderRadius: "6px",
|
|
92
|
-
flexWrap: "nowrap",
|
|
93
|
-
gap: "2px",
|
|
94
|
-
padding: "2px",
|
|
95
|
-
width: "fit-content",
|
|
96
|
-
// Button (including dropdown target)
|
|
97
|
-
".mantine-UnstyledButton-root": {
|
|
98
|
-
borderRadius: "4px",
|
|
99
|
-
},
|
|
100
|
-
// Dropdown
|
|
101
|
-
".mantine-Menu-dropdown": {
|
|
102
|
-
// Dropdown item
|
|
103
|
-
".mantine-Menu-item": {
|
|
104
|
-
color: theme.colors.brandFinal,
|
|
105
|
-
fontSize: "12px",
|
|
106
|
-
height: "34px",
|
|
107
|
-
".mantine-Menu-itemRightSection": {
|
|
108
|
-
paddingLeft: "5px",
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
}),
|
|
114
|
-
},
|
|
115
|
-
SuggestionList: {
|
|
116
|
-
styles: (theme) => ({
|
|
117
|
-
root: {
|
|
118
|
-
// ...theme.other.defaultMenuStyles(theme),
|
|
119
|
-
".mantine-Menu-item": {
|
|
120
|
-
// Icon
|
|
121
|
-
".mantine-Menu-itemIcon": {
|
|
122
|
-
padding: "8px",
|
|
123
|
-
border: `1px solid ${theme.colors.brandFinal[2]}`,
|
|
124
|
-
backgroundColor: theme.colors.brandFinal[0],
|
|
125
|
-
borderRadius: "4px",
|
|
126
|
-
color: theme.colors.brandFinal,
|
|
127
|
-
},
|
|
128
|
-
// Text
|
|
129
|
-
".mantine-Menu-itemLabel": {
|
|
130
|
-
color: theme.colors.brandFinal,
|
|
131
|
-
paddingRight: "16px",
|
|
132
|
-
".mantine-Stack-root": {
|
|
133
|
-
gap: "0",
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
// Badge (keyboard shortcut)
|
|
137
|
-
".mantine-Menu-itemRightSection": {
|
|
138
|
-
".mantine-Badge-root": {
|
|
139
|
-
border: `1px solid ${theme.colors.brandFinal[2]}`,
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
}),
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
fontFamily: "Inter",
|
|
148
|
-
primaryColor: "brandFinal",
|
|
149
|
-
primaryShade: 9,
|
|
150
|
-
};
|
package/src/EditorContent.tsx
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Plugin, PluginKey } from "prosemirror-state";
|
|
2
|
-
|
|
3
|
-
const PLUGIN_KEY = new PluginKey(`ordered-list`);
|
|
4
|
-
|
|
5
|
-
export const OrderedListPlugin = () => {
|
|
6
|
-
return new Plugin({
|
|
7
|
-
key: PLUGIN_KEY,
|
|
8
|
-
appendTransaction: (_transactions, _oldState, newState) => {
|
|
9
|
-
const newTr = newState.tr;
|
|
10
|
-
let modified = false;
|
|
11
|
-
let count = 1;
|
|
12
|
-
let skip = 0;
|
|
13
|
-
newState.doc.descendants((node, pos) => {
|
|
14
|
-
if (node.type.name === "block" && !node.attrs.listType) {
|
|
15
|
-
count = 1;
|
|
16
|
-
}
|
|
17
|
-
if (
|
|
18
|
-
skip === 0 &&
|
|
19
|
-
node.type.name === "block" &&
|
|
20
|
-
node.attrs.listType === "oli"
|
|
21
|
-
) {
|
|
22
|
-
skip = node.content.childCount;
|
|
23
|
-
// This assumes that the content node is always the first child of the oli block,
|
|
24
|
-
// as the content model grows this assumption may need to change
|
|
25
|
-
if (node.content.child(0).attrs.position !== `${count}.`) {
|
|
26
|
-
// TODO: @DAlperin currently sub-items just continue from the order of the parent,
|
|
27
|
-
// sub-items should be ordered separately with letters or roman numerals or some such
|
|
28
|
-
newTr.setNodeMarkup(pos + 1, undefined, {
|
|
29
|
-
...node.attrs,
|
|
30
|
-
position: `${count}.`,
|
|
31
|
-
});
|
|
32
|
-
modified = true;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
count++;
|
|
36
|
-
} else if (skip > 0) {
|
|
37
|
-
skip--;
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
if (modified) {
|
|
41
|
-
return newTr;
|
|
42
|
-
}
|
|
43
|
-
return null;
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
};
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
import { Fragment, Node, ResolvedPos, Slice } from "prosemirror-model";
|
|
2
|
-
import { EditorState, NodeSelection, Selection } from "prosemirror-state";
|
|
3
|
-
import {
|
|
4
|
-
canJoin,
|
|
5
|
-
liftTarget,
|
|
6
|
-
ReplaceAroundStep,
|
|
7
|
-
replaceStep,
|
|
8
|
-
} from "prosemirror-transform";
|
|
9
|
-
|
|
10
|
-
import { Command, TextSelection, Transaction } from "prosemirror-state";
|
|
11
|
-
import { ReplaceStep } from "prosemirror-transform";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Code taken from https://github.com/ProseMirror/prosemirror-commands/blob/97a8cb5fac25e697d4693ce343e2e3b020a7fa2f/src/commands.ts
|
|
15
|
-
* Reason for modification: https://github.com/YousefED/BlockNote/pull/11
|
|
16
|
-
*
|
|
17
|
-
* BlockA
|
|
18
|
-
* BlockB
|
|
19
|
-
* Order of behavior has been switched to make first and second blocks content
|
|
20
|
-
* merge before trying to add second block as child of first
|
|
21
|
-
*
|
|
22
|
-
* behavior responsible for joining BlockB as A child of BlockA moved to (line 379 - 393 original file) after
|
|
23
|
-
* behavior responsible for joining content of BlockA and BlockB (line 402 - 422 original file)
|
|
24
|
-
*/
|
|
25
|
-
export const joinBackward: Command = (state, dispatch, view) => {
|
|
26
|
-
let { $cursor } = state.selection as TextSelection;
|
|
27
|
-
if (
|
|
28
|
-
!$cursor ||
|
|
29
|
-
(view ? !view.endOfTextblock("backward", state) : $cursor.parentOffset > 0)
|
|
30
|
-
) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let $cut = findCutBefore($cursor);
|
|
35
|
-
|
|
36
|
-
// If there is no node before this, try to lift
|
|
37
|
-
if (!$cut) {
|
|
38
|
-
let range = $cursor.blockRange(),
|
|
39
|
-
target = range && liftTarget(range);
|
|
40
|
-
if (target === null) {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
if (dispatch) {
|
|
44
|
-
dispatch(state.tr.lift(range!, target).scrollIntoView());
|
|
45
|
-
}
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
let before = $cut.nodeBefore!;
|
|
50
|
-
// Apply the joining algorithm
|
|
51
|
-
if (!before.type.spec.isolating && deleteBarrier(state, $cut, dispatch)) {
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// If the node below has no content and the node above is
|
|
56
|
-
// selectable, delete the node below and select the one above.
|
|
57
|
-
if (
|
|
58
|
-
$cursor.parent.content.size === 0 &&
|
|
59
|
-
(textblockAt(before, "end") || NodeSelection.isSelectable(before))
|
|
60
|
-
) {
|
|
61
|
-
let delStep = replaceStep(
|
|
62
|
-
state.doc,
|
|
63
|
-
$cursor.before(),
|
|
64
|
-
$cursor.after(),
|
|
65
|
-
Slice.empty
|
|
66
|
-
);
|
|
67
|
-
if (
|
|
68
|
-
delStep &&
|
|
69
|
-
(delStep as ReplaceStep).slice.size <
|
|
70
|
-
(delStep as ReplaceStep).to - (delStep as ReplaceStep).from
|
|
71
|
-
) {
|
|
72
|
-
if (dispatch) {
|
|
73
|
-
let tr = state.tr.step(delStep);
|
|
74
|
-
tr.setSelection(
|
|
75
|
-
textblockAt(before, "end")
|
|
76
|
-
? Selection.findFrom(
|
|
77
|
-
tr.doc.resolve(tr.mapping.map($cut.pos, -1)),
|
|
78
|
-
-1
|
|
79
|
-
)!
|
|
80
|
-
: NodeSelection.create(tr.doc, $cut.pos - before.nodeSize)
|
|
81
|
-
);
|
|
82
|
-
dispatch(tr.scrollIntoView());
|
|
83
|
-
}
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// If the node before is an atom, delete it
|
|
89
|
-
if (before.isAtom && $cut.depth === $cursor.depth - 1) {
|
|
90
|
-
if (dispatch) {
|
|
91
|
-
dispatch(
|
|
92
|
-
state.tr.delete($cut.pos - before.nodeSize, $cut.pos).scrollIntoView()
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
return true;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return false;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
function findCutBefore($pos: ResolvedPos): ResolvedPos | null {
|
|
102
|
-
if (!$pos.parent.type.spec.isolating) {
|
|
103
|
-
for (let i = $pos.depth - 1; i >= 0; i--) {
|
|
104
|
-
if ($pos.index(i) > 0) {
|
|
105
|
-
return $pos.doc.resolve($pos.before(i + 1));
|
|
106
|
-
}
|
|
107
|
-
if ($pos.node(i).type.spec.isolating) {
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function deleteBarrier(
|
|
116
|
-
state: EditorState,
|
|
117
|
-
$cut: ResolvedPos,
|
|
118
|
-
dispatch: ((tr: Transaction) => void) | undefined
|
|
119
|
-
) {
|
|
120
|
-
let before = $cut.nodeBefore!,
|
|
121
|
-
after = $cut.nodeAfter!,
|
|
122
|
-
conn,
|
|
123
|
-
match;
|
|
124
|
-
if (before.type.spec.isolating || after.type.spec.isolating) {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
if (joinMaybeClear(state, $cut, dispatch)) {
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
let canDelAfter = $cut.parent.canReplace($cut.index(), $cut.index() + 1);
|
|
132
|
-
|
|
133
|
-
let selAfter = Selection.findFrom($cut, 1);
|
|
134
|
-
let range = selAfter && selAfter.$from.blockRange(selAfter.$to),
|
|
135
|
-
target = range && liftTarget(range);
|
|
136
|
-
if (target != null && target >= $cut.depth) {
|
|
137
|
-
if (dispatch) {
|
|
138
|
-
dispatch(state.tr.lift(range!, target).scrollIntoView());
|
|
139
|
-
}
|
|
140
|
-
return true;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (
|
|
144
|
-
canDelAfter &&
|
|
145
|
-
textblockAt(after, "start", true) &&
|
|
146
|
-
textblockAt(before, "end")
|
|
147
|
-
) {
|
|
148
|
-
let at = before,
|
|
149
|
-
wrap = [];
|
|
150
|
-
for (;;) {
|
|
151
|
-
wrap.push(at);
|
|
152
|
-
if (at.isTextblock) {
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
at = at.lastChild!;
|
|
156
|
-
}
|
|
157
|
-
let afterText = after,
|
|
158
|
-
afterDepth = 1;
|
|
159
|
-
for (; !afterText.isTextblock; afterText = afterText.firstChild!) {
|
|
160
|
-
afterDepth++;
|
|
161
|
-
}
|
|
162
|
-
if (at.canReplace(at.childCount, at.childCount, afterText.content)) {
|
|
163
|
-
if (dispatch) {
|
|
164
|
-
let end = Fragment.empty;
|
|
165
|
-
for (let i = wrap.length - 1; i >= 0; i--) {
|
|
166
|
-
end = Fragment.from(wrap[i].copy(end));
|
|
167
|
-
}
|
|
168
|
-
let tr = state.tr.step(
|
|
169
|
-
new ReplaceAroundStep(
|
|
170
|
-
$cut.pos - wrap.length,
|
|
171
|
-
$cut.pos + after.nodeSize,
|
|
172
|
-
$cut.pos + afterDepth,
|
|
173
|
-
$cut.pos + after.nodeSize - afterDepth,
|
|
174
|
-
new Slice(end, wrap.length, 0),
|
|
175
|
-
0,
|
|
176
|
-
true
|
|
177
|
-
)
|
|
178
|
-
);
|
|
179
|
-
dispatch(tr.scrollIntoView());
|
|
180
|
-
}
|
|
181
|
-
return true;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
canDelAfter &&
|
|
187
|
-
(conn = (match = before.contentMatchAt(before.childCount)).findWrapping(
|
|
188
|
-
after.type
|
|
189
|
-
)) &&
|
|
190
|
-
match.matchType(conn[0] || after.type)!.validEnd
|
|
191
|
-
) {
|
|
192
|
-
if (dispatch) {
|
|
193
|
-
let end = $cut.pos + after.nodeSize,
|
|
194
|
-
wrap = Fragment.empty;
|
|
195
|
-
for (let i = conn.length - 1; i >= 0; i--) {
|
|
196
|
-
wrap = Fragment.from(conn[i].create(null, wrap));
|
|
197
|
-
}
|
|
198
|
-
wrap = Fragment.from(before.copy(wrap));
|
|
199
|
-
let tr = state.tr.step(
|
|
200
|
-
new ReplaceAroundStep(
|
|
201
|
-
$cut.pos - 1,
|
|
202
|
-
end,
|
|
203
|
-
$cut.pos,
|
|
204
|
-
end,
|
|
205
|
-
new Slice(wrap, 1, 0),
|
|
206
|
-
conn.length,
|
|
207
|
-
true
|
|
208
|
-
)
|
|
209
|
-
);
|
|
210
|
-
let joinAt = end + 2 * conn.length;
|
|
211
|
-
if (canJoin(tr.doc, joinAt)) {
|
|
212
|
-
tr.join(joinAt);
|
|
213
|
-
}
|
|
214
|
-
dispatch(tr.scrollIntoView());
|
|
215
|
-
}
|
|
216
|
-
return true;
|
|
217
|
-
}
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function textblockAt(node: Node, side: "start" | "end", only = false) {
|
|
222
|
-
for (
|
|
223
|
-
let scan: Node | null = node;
|
|
224
|
-
scan;
|
|
225
|
-
scan = side === "start" ? scan.firstChild : scan.lastChild
|
|
226
|
-
) {
|
|
227
|
-
if (scan.isTextblock) {
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
if (only && scan.childCount !== 1) {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
function joinMaybeClear(
|
|
237
|
-
state: EditorState,
|
|
238
|
-
$pos: ResolvedPos,
|
|
239
|
-
dispatch: ((tr: Transaction) => void) | undefined
|
|
240
|
-
) {
|
|
241
|
-
let before = $pos.nodeBefore,
|
|
242
|
-
after = $pos.nodeAfter,
|
|
243
|
-
index = $pos.index();
|
|
244
|
-
if (!before || !after || !before.type.compatibleContent(after.type)) {
|
|
245
|
-
return false;
|
|
246
|
-
}
|
|
247
|
-
if (!before.content.size && $pos.parent.canReplace(index - 1, index)) {
|
|
248
|
-
if (dispatch) {
|
|
249
|
-
dispatch(
|
|
250
|
-
state.tr.delete($pos.pos - before.nodeSize, $pos.pos).scrollIntoView()
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
return true;
|
|
254
|
-
}
|
|
255
|
-
if (
|
|
256
|
-
!$pos.parent.canReplace(index, index + 1) ||
|
|
257
|
-
!(after.isTextblock || canJoin(state.doc, $pos.pos))
|
|
258
|
-
) {
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
if (dispatch) {
|
|
262
|
-
dispatch(
|
|
263
|
-
state.tr
|
|
264
|
-
.clearIncompatible(
|
|
265
|
-
$pos.pos,
|
|
266
|
-
before.type,
|
|
267
|
-
before.contentMatchAt(before.childCount)
|
|
268
|
-
)
|
|
269
|
-
.join($pos.pos)
|
|
270
|
-
.scrollIntoView()
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
return true;
|
|
274
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Transaction } from "prosemirror-state";
|
|
2
|
-
import { Level } from "../nodes/Block";
|
|
3
|
-
import { findBlock } from "./findBlock";
|
|
4
|
-
|
|
5
|
-
type Dispatch = ((args?: any) => any) | undefined;
|
|
6
|
-
|
|
7
|
-
export function setBlockHeading(
|
|
8
|
-
tr: Transaction,
|
|
9
|
-
dispatch: Dispatch,
|
|
10
|
-
level?: Level
|
|
11
|
-
) {
|
|
12
|
-
// Get parent of TextNode
|
|
13
|
-
const containingBlock = findBlock(tr.selection);
|
|
14
|
-
|
|
15
|
-
// Should not be possible because schema dictates
|
|
16
|
-
// that each text node is nested in a BlockContent
|
|
17
|
-
// node which is nested inside a BlockNode
|
|
18
|
-
if (!containingBlock) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Add heading attribute to Block
|
|
23
|
-
if (dispatch) {
|
|
24
|
-
tr.setNodeMarkup(containingBlock.pos, undefined, {
|
|
25
|
-
...containingBlock.node.attrs,
|
|
26
|
-
headingType: level,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { mergeAttributes, Node } from "@tiptap/core";
|
|
2
|
-
import styles from "./Block.module.css";
|
|
3
|
-
export interface IBlock {
|
|
4
|
-
HTMLAttributes: Record<string, any>;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export const ContentBlock = Node.create<IBlock>({
|
|
8
|
-
name: "content",
|
|
9
|
-
|
|
10
|
-
addOptions() {
|
|
11
|
-
return {
|
|
12
|
-
HTMLAttributes: {},
|
|
13
|
-
};
|
|
14
|
-
},
|
|
15
|
-
addAttributes() {
|
|
16
|
-
return {
|
|
17
|
-
position: {
|
|
18
|
-
default: undefined,
|
|
19
|
-
renderHTML: (attributes) => {
|
|
20
|
-
return {
|
|
21
|
-
"data-position": attributes.position,
|
|
22
|
-
};
|
|
23
|
-
},
|
|
24
|
-
parseHTML: (element) => element.getAttribute("data-position"),
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
content: "inline*",
|
|
30
|
-
|
|
31
|
-
parseHTML() {
|
|
32
|
-
return [
|
|
33
|
-
{
|
|
34
|
-
tag: "div",
|
|
35
|
-
getAttrs: (element) => {
|
|
36
|
-
if(typeof element === "string") {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if(element.getAttribute("data-node-type") === "block-content") {
|
|
41
|
-
// Null means the element matches, but we don't want to add any attributes to the node.
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
];
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
renderHTML({ HTMLAttributes }) {
|
|
52
|
-
return [
|
|
53
|
-
"div",
|
|
54
|
-
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
55
|
-
class: styles.blockContent,
|
|
56
|
-
"data-node-type": "block-content"
|
|
57
|
-
}),
|
|
58
|
-
// TODO: The extra nested div is only needed for placeholders, different solution (without extra div) would be preferable
|
|
59
|
-
// We can't use the other div because the ::before attribute on that one is already reserved for list-bullets
|
|
60
|
-
["div", 0],
|
|
61
|
-
];
|
|
62
|
-
},
|
|
63
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
callOrReturn,
|
|
3
|
-
ExtendedRegExpMatchArray,
|
|
4
|
-
InputRule,
|
|
5
|
-
InputRuleFinder,
|
|
6
|
-
} from "@tiptap/core";
|
|
7
|
-
import { NodeType } from "prosemirror-model";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Modified version of https://github.com/ueberdosis/tiptap/blob/6a813686f5e87cebac49a624936dbeadb5a29f95/packages/core/src/inputRules/textblockTypeInputRule.ts
|
|
11
|
-
* But instead of changing the type of a node, we use setNodeMarkup to change some of it's current attributes
|
|
12
|
-
*
|
|
13
|
-
* Build an input rule that changes the type of a textblock when the
|
|
14
|
-
* matched text is typed into it. When using a regular expresion you’ll
|
|
15
|
-
* probably want the regexp to start with `^`, so that the pattern can
|
|
16
|
-
* only occur at the start of a textblock.
|
|
17
|
-
*/
|
|
18
|
-
export function textblockTypeInputRuleSameNodeType(config: {
|
|
19
|
-
find: InputRuleFinder;
|
|
20
|
-
type: NodeType;
|
|
21
|
-
getAttributes?:
|
|
22
|
-
| Record<string, any>
|
|
23
|
-
| ((match: ExtendedRegExpMatchArray) => Record<string, any>)
|
|
24
|
-
| false
|
|
25
|
-
| null;
|
|
26
|
-
}) {
|
|
27
|
-
return new InputRule({
|
|
28
|
-
find: config.find,
|
|
29
|
-
handler: ({ state, range, match }) => {
|
|
30
|
-
const $start = state.doc.resolve(range.from);
|
|
31
|
-
const attributes =
|
|
32
|
-
callOrReturn(config.getAttributes, undefined, match) || {};
|
|
33
|
-
|
|
34
|
-
const blockNode = $start.node(-1);
|
|
35
|
-
if (blockNode.type !== config.type) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
state.tr
|
|
40
|
-
.setNodeMarkup(range.from - 2, undefined, {
|
|
41
|
-
...blockNode.attrs,
|
|
42
|
-
...attributes,
|
|
43
|
-
})
|
|
44
|
-
.delete(range.from, range.to);
|
|
45
|
-
return;
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { MantineProvider } from "@mantine/core";
|
|
2
|
-
import { Extension } from "@tiptap/core";
|
|
3
|
-
import { PluginKey } from "prosemirror-state";
|
|
4
|
-
import ReactDOM from "react-dom";
|
|
5
|
-
import { BlockNoteTheme } from "../../BlockNoteTheme";
|
|
6
|
-
import rootStyles from "../../root.module.css";
|
|
7
|
-
import { createBubbleMenuPlugin } from "./BubbleMenuPlugin";
|
|
8
|
-
import { BubbleMenu } from "./component/BubbleMenu";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* The menu that is displayed when selecting a piece of text.
|
|
12
|
-
*/
|
|
13
|
-
export const BubbleMenuExtension = Extension.create<{}>({
|
|
14
|
-
name: "BubbleMenuExtension",
|
|
15
|
-
|
|
16
|
-
addProseMirrorPlugins() {
|
|
17
|
-
const element = document.createElement("div");
|
|
18
|
-
element.className = rootStyles.bnRoot;
|
|
19
|
-
ReactDOM.render(
|
|
20
|
-
<MantineProvider theme={BlockNoteTheme}>
|
|
21
|
-
<BubbleMenu editor={this.editor} />
|
|
22
|
-
</MantineProvider>,
|
|
23
|
-
element
|
|
24
|
-
);
|
|
25
|
-
return [
|
|
26
|
-
createBubbleMenuPlugin({
|
|
27
|
-
editor: this.editor,
|
|
28
|
-
element,
|
|
29
|
-
pluginKey: new PluginKey("BubbleMenuPlugin"),
|
|
30
|
-
tippyOptions: {
|
|
31
|
-
appendTo: document.body,
|
|
32
|
-
},
|
|
33
|
-
}),
|
|
34
|
-
];
|
|
35
|
-
},
|
|
36
|
-
});
|