@blocknote/core 0.42.3 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BlockNoteExtension-BWw0r8Gy.cjs +2 -0
- package/dist/BlockNoteExtension-BWw0r8Gy.cjs.map +1 -0
- package/dist/BlockNoteExtension-C2X7LW-V.js +25 -0
- package/dist/BlockNoteExtension-C2X7LW-V.js.map +1 -0
- package/dist/BlockNoteSchema-B4gm-Qco.cjs +2 -0
- package/dist/BlockNoteSchema-B4gm-Qco.cjs.map +1 -0
- package/dist/BlockNoteSchema-C-l154WP.js +270 -0
- package/dist/BlockNoteSchema-C-l154WP.js.map +1 -0
- package/dist/EventEmitter-CLwfmbqG.cjs +2 -0
- package/dist/EventEmitter-CLwfmbqG.cjs.map +1 -0
- package/dist/EventEmitter-CjSwpTbz.js +27 -0
- package/dist/EventEmitter-CjSwpTbz.js.map +1 -0
- package/dist/ShowSelection-BW37oJ6h.cjs +2 -0
- package/dist/ShowSelection-BW37oJ6h.cjs.map +1 -0
- package/dist/ShowSelection-Dz-NEase.js +43 -0
- package/dist/ShowSelection-Dz-NEase.js.map +1 -0
- package/dist/TrailingNode-B_zPMWxw.js +2098 -0
- package/dist/TrailingNode-B_zPMWxw.js.map +1 -0
- package/dist/TrailingNode-CRHrgOnK.cjs +2 -0
- package/dist/TrailingNode-CRHrgOnK.cjs.map +1 -0
- package/dist/{blockToNode-DIfPWLH8.js → blockToNode-DBNbhwwC.js} +33 -33
- package/dist/blockToNode-DBNbhwwC.js.map +1 -0
- package/dist/blockToNode-w7H99R6p.cjs.map +1 -1
- package/dist/blocknote.cjs +4 -4
- package/dist/blocknote.cjs.map +1 -1
- package/dist/blocknote.js +2496 -5686
- package/dist/blocknote.js.map +1 -1
- package/dist/blocks.cjs +1 -1
- package/dist/blocks.js +71 -70
- package/dist/blocks.js.map +1 -1
- package/dist/comments.cjs +1 -1
- package/dist/comments.cjs.map +1 -1
- package/dist/comments.js +451 -137
- package/dist/comments.js.map +1 -1
- package/dist/defaultBlocks-DLJ4Q1_J.cjs +6 -0
- package/dist/defaultBlocks-DLJ4Q1_J.cjs.map +1 -0
- package/dist/{BlockNoteSchema-Bi-eeHal.js → defaultBlocks-DgA_mtQV.js} +974 -1027
- package/dist/defaultBlocks-DgA_mtQV.js.map +1 -0
- package/dist/extensions.cjs +2 -0
- package/dist/extensions.cjs.map +1 -0
- package/dist/extensions.js +57 -0
- package/dist/extensions.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/dist/yjs.js +1 -1
- package/package.json +9 -3
- package/src/api/nodeConversions/blockToNode.ts +1 -1
- package/src/api/nodeConversions/nodeToBlock.ts +1 -1
- package/src/blocks/Code/block.ts +4 -4
- package/src/blocks/Divider/block.ts +2 -2
- package/src/blocks/File/helpers/render/createAddFileButton.ts +7 -5
- package/src/blocks/Heading/block.ts +23 -20
- package/src/blocks/ListItem/BulletListItem/block.ts +2 -2
- package/src/blocks/ListItem/CheckListItem/block.ts +2 -2
- package/src/blocks/ListItem/NumberedListItem/block.ts +3 -3
- package/src/blocks/ListItem/ToggleListItem/block.ts +2 -2
- package/src/blocks/PageBreak/getPageBreakSlashMenuItems.ts +2 -2
- package/src/blocks/Paragraph/block.ts +2 -2
- package/src/blocks/Quote/block.ts +2 -2
- package/src/blocks/Table/block.ts +4 -3
- package/src/blocks/ToggleWrapper/createToggleWrapper.ts +2 -1
- package/src/comments/extension.ts +353 -0
- package/src/comments/index.ts +2 -1
- package/src/comments/types.ts +8 -0
- package/src/{extensions/Comments → comments}/userstore/UserStore.ts +2 -2
- package/src/editor/BlockNoteEditor.test.ts +2 -23
- package/src/editor/BlockNoteEditor.ts +60 -453
- package/src/editor/BlockNoteExtension.test.ts +103 -0
- package/src/editor/BlockNoteExtension.ts +174 -56
- package/src/editor/managers/EventManager.ts +64 -35
- package/src/editor/managers/ExtensionManager/extensions.ts +214 -0
- package/src/editor/managers/ExtensionManager/index.ts +514 -0
- package/src/editor/managers/ExtensionManager/symbol.ts +6 -0
- package/src/editor/managers/SelectionManager.ts +5 -1
- package/src/editor/managers/StateManager.ts +29 -17
- package/src/editor/managers/index.ts +1 -5
- package/src/extensions/BlockChange/{BlockChangePlugin.ts → BlockChange.ts} +27 -29
- package/src/extensions/Collaboration/{ForkYDocPlugin.test.ts → ForkYDoc.test.ts} +6 -5
- package/src/extensions/Collaboration/ForkYDoc.ts +158 -0
- package/src/extensions/Collaboration/YCursorPlugin.ts +183 -0
- package/src/extensions/Collaboration/YSync.ts +16 -0
- package/src/extensions/Collaboration/YUndo.ts +12 -0
- package/src/extensions/Collaboration/schemaMigration/SchemaMigration.ts +59 -0
- package/src/extensions/DropCursor/DropCursor.ts +26 -0
- package/src/extensions/FilePanel/FilePanel.ts +41 -0
- package/src/extensions/FormattingToolbar/FormattingToolbar.ts +119 -0
- package/src/extensions/History/History.ts +11 -0
- package/src/extensions/LinkToolbar/LinkToolbar.ts +121 -0
- package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboard.ts +74 -0
- package/src/extensions/Placeholder/Placeholder.ts +148 -0
- package/src/extensions/PreviousBlockType/{PreviousBlockTypePlugin.ts → PreviousBlockType.ts} +9 -13
- package/src/extensions/ShowSelection/{ShowSelectionPlugin.ts → ShowSelection.ts} +27 -33
- package/src/extensions/SideMenu/{SideMenuPlugin.ts → SideMenu.ts} +63 -83
- package/src/extensions/SuggestionMenu/{SuggestionPlugin.ts → SuggestionMenu.ts} +71 -77
- package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +29 -44
- package/src/extensions/TableHandles/{TableHandlesPlugin.ts → TableHandles.ts} +416 -437
- package/src/extensions/TrailingNode/{TrailingNodeExtension.ts → TrailingNode.ts} +8 -17
- package/src/extensions/index.ts +24 -0
- package/src/extensions/{BackgroundColor → tiptap-extensions/BackgroundColor}/BackgroundColorExtension.ts +1 -1
- package/src/extensions/{KeyboardShortcuts → tiptap-extensions/KeyboardShortcuts}/KeyboardShortcutsExtension.ts +21 -16
- package/src/extensions/{TextColor → tiptap-extensions/TextColor}/TextColorExtension.ts +1 -1
- package/src/extensions/tiptap-extensions/index.ts +31 -0
- package/src/index.ts +1 -13
- package/src/schema/blocks/createSpec.ts +14 -11
- package/src/schema/blocks/internal.ts +2 -2
- package/src/schema/blocks/types.ts +8 -5
- package/src/schema/schema.ts +11 -36
- package/src/util/topo-sort.ts +46 -0
- package/types/src/comments/extension.d.ts +70 -0
- package/types/src/comments/index.d.ts +2 -1
- package/types/src/comments/types.d.ts +8 -0
- package/types/src/{extensions/Comments → comments}/userstore/UserStore.d.ts +2 -2
- package/types/src/editor/BlockNoteEditor.d.ts +34 -105
- package/types/src/editor/BlockNoteExtension.d.ts +87 -22
- package/types/src/editor/managers/EventManager.d.ts +25 -16
- package/types/src/editor/managers/ExtensionManager/extensions.d.ts +8 -0
- package/types/src/editor/managers/ExtensionManager/index.d.ts +83 -0
- package/types/src/editor/managers/ExtensionManager/symbol.d.ts +5 -0
- package/types/src/editor/managers/StateManager.d.ts +1 -12
- package/types/src/editor/managers/index.d.ts +1 -2
- package/types/src/extensions/BlockChange/BlockChange.d.ts +16 -0
- package/types/src/extensions/Collaboration/ForkYDoc.d.ts +34 -0
- package/types/src/extensions/Collaboration/ForkYDoc.test.d.ts +1 -0
- package/types/src/extensions/Collaboration/YCursorPlugin.d.ts +24 -0
- package/types/src/extensions/Collaboration/YSync.d.ts +8 -0
- package/types/src/extensions/Collaboration/YUndo.d.ts +12 -0
- package/types/src/extensions/Collaboration/schemaMigration/SchemaMigration.d.ts +8 -0
- package/types/src/extensions/DropCursor/DropCursor.d.ts +5 -0
- package/types/src/extensions/FilePanel/FilePanel.d.ts +11 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbar.d.ts +9 -0
- package/types/src/extensions/History/History.d.ts +6 -0
- package/types/src/extensions/LinkToolbar/LinkToolbar.d.ts +24 -0
- package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboard.d.ts +5 -0
- package/types/src/extensions/Placeholder/Placeholder.d.ts +6 -0
- package/types/src/extensions/PreviousBlockType/{PreviousBlockTypePlugin.d.ts → PreviousBlockType.d.ts} +9 -5
- package/types/src/extensions/ShowSelection/ShowSelection.d.ts +21 -0
- package/types/src/extensions/SideMenu/{SideMenuPlugin.d.ts → SideMenu.d.ts} +11 -15
- package/types/src/extensions/SuggestionMenu/SuggestionMenu.d.ts +54 -0
- package/types/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.d.ts +1 -1
- package/types/src/extensions/TableHandles/{TableHandlesPlugin.d.ts → TableHandles.d.ts} +28 -31
- package/types/src/extensions/TrailingNode/TrailingNode.d.ts +8 -0
- package/types/src/extensions/index.d.ts +24 -0
- package/types/src/extensions/{KeyboardShortcuts → tiptap-extensions/KeyboardShortcuts}/KeyboardShortcutsExtension.d.ts +1 -1
- package/types/src/extensions/tiptap-extensions/index.d.ts +11 -0
- package/types/src/index.d.ts +1 -13
- package/types/src/schema/blocks/createSpec.d.ts +4 -4
- package/types/src/schema/blocks/internal.d.ts +2 -2
- package/types/src/schema/blocks/types.d.ts +5 -5
- package/types/src/util/topo-sort.d.ts +8 -0
- package/dist/BlockNoteSchema-Bi-eeHal.js.map +0 -1
- package/dist/BlockNoteSchema-DjDaA2C3.cjs +0 -6
- package/dist/BlockNoteSchema-DjDaA2C3.cjs.map +0 -1
- package/dist/blockToNode-DIfPWLH8.js.map +0 -1
- package/src/comments/models/User.ts +0 -8
- package/src/editor/BlockNoteExtensions.ts +0 -325
- package/src/editor/managers/CollaborationManager.ts +0 -212
- package/src/editor/managers/ExtensionManager.ts +0 -130
- package/src/extensions/Collaboration/CursorPlugin.ts +0 -189
- package/src/extensions/Collaboration/ForkYDocPlugin.ts +0 -192
- package/src/extensions/Collaboration/SyncPlugin.ts +0 -18
- package/src/extensions/Collaboration/UndoPlugin.ts +0 -18
- package/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts +0 -59
- package/src/extensions/Comments/CommentsPlugin.ts +0 -392
- package/src/extensions/FilePanel/FilePanelPlugin.ts +0 -206
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +0 -363
- package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +0 -380
- package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts +0 -75
- package/src/extensions/Placeholder/PlaceholderPlugin.ts +0 -147
- package/types/src/comments/models/User.d.ts +0 -8
- package/types/src/editor/BlockNoteExtensions.d.ts +0 -43
- package/types/src/editor/managers/CollaborationManager.d.ts +0 -115
- package/types/src/editor/managers/ExtensionManager.d.ts +0 -68
- package/types/src/extensions/BlockChange/BlockChangePlugin.d.ts +0 -15
- package/types/src/extensions/Collaboration/CursorPlugin.d.ts +0 -37
- package/types/src/extensions/Collaboration/ForkYDocPlugin.d.ts +0 -41
- package/types/src/extensions/Collaboration/SyncPlugin.d.ts +0 -7
- package/types/src/extensions/Collaboration/UndoPlugin.d.ts +0 -9
- package/types/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.d.ts +0 -7
- package/types/src/extensions/Comments/CommentsPlugin.d.ts +0 -66
- package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +0 -31
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +0 -41
- package/types/src/extensions/LinkToolbar/LinkToolbarPlugin.d.ts +0 -42
- package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.d.ts +0 -5
- package/types/src/extensions/Placeholder/PlaceholderPlugin.d.ts +0 -6
- package/types/src/extensions/ShowSelection/ShowSelectionPlugin.d.ts +0 -15
- package/types/src/extensions/SuggestionMenu/SuggestionPlugin.d.ts +0 -31
- package/types/src/extensions/TrailingNode/TrailingNodeExtension.d.ts +0 -13
- /package/src/{extensions/Comments/CommentMark.ts → comments/mark.ts} +0 -0
- /package/src/extensions/{HardBreak → tiptap-extensions/HardBreak}/HardBreak.ts +0 -0
- /package/src/extensions/{Suggestions → tiptap-extensions/Suggestions}/SuggestionMarks.ts +0 -0
- /package/src/extensions/{TextAlignment → tiptap-extensions/TextAlignment}/TextAlignmentExtension.ts +0 -0
- /package/src/extensions/{UniqueID → tiptap-extensions/UniqueID}/UniqueID.ts +0 -0
- /package/types/src/{extensions/Comments/CommentMark.d.ts → comments/mark.d.ts} +0 -0
- /package/types/src/{extensions/Collaboration/ForkYDocPlugin.test.d.ts → editor/BlockNoteExtension.test.d.ts} +0 -0
- /package/types/src/extensions/{BackgroundColor → tiptap-extensions/BackgroundColor}/BackgroundColorExtension.d.ts +0 -0
- /package/types/src/extensions/{HardBreak → tiptap-extensions/HardBreak}/HardBreak.d.ts +0 -0
- /package/types/src/extensions/{Suggestions → tiptap-extensions/Suggestions}/SuggestionMarks.d.ts +0 -0
- /package/types/src/extensions/{TextAlignment → tiptap-extensions/TextAlignment}/TextAlignmentExtension.d.ts +0 -0
- /package/types/src/extensions/{TextColor → tiptap-extensions/TextColor}/TextColorExtension.d.ts +0 -0
- /package/types/src/extensions/{UniqueID → tiptap-extensions/UniqueID}/UniqueID.d.ts +0 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { getMarkRange, posToDOMRect } from "@tiptap/core";
|
|
2
|
+
import { createExtension } from "../../editor/BlockNoteExtension.js";
|
|
3
|
+
import { getPmSchema } from "../../api/pmUtil.js";
|
|
4
|
+
|
|
5
|
+
export const LinkToolbarExtension = createExtension(({ editor }) => {
|
|
6
|
+
function getLinkElementAtPos(pos: number) {
|
|
7
|
+
let currentNode = editor.prosemirrorView.nodeDOM(pos);
|
|
8
|
+
while (currentNode && currentNode.parentElement) {
|
|
9
|
+
if (currentNode.nodeName === "A") {
|
|
10
|
+
return currentNode as HTMLAnchorElement;
|
|
11
|
+
}
|
|
12
|
+
currentNode = currentNode.parentElement;
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getMarkAtPos(pos: number, markType: string) {
|
|
18
|
+
return editor.transact((tr) => {
|
|
19
|
+
const resolvedPos = tr.doc.resolve(pos);
|
|
20
|
+
const mark = resolvedPos
|
|
21
|
+
.marks()
|
|
22
|
+
.find((mark) => mark.type.name === markType);
|
|
23
|
+
|
|
24
|
+
if (!mark) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const markRange = getMarkRange(resolvedPos, mark.type);
|
|
29
|
+
if (!markRange) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
range: markRange,
|
|
35
|
+
mark,
|
|
36
|
+
get text() {
|
|
37
|
+
return tr.doc.textBetween(markRange.from, markRange.to);
|
|
38
|
+
},
|
|
39
|
+
get position() {
|
|
40
|
+
// to minimize re-renders, we convert to JSON, which is the same shape anyway
|
|
41
|
+
return posToDOMRect(
|
|
42
|
+
editor.prosemirrorView,
|
|
43
|
+
markRange.from,
|
|
44
|
+
markRange.to,
|
|
45
|
+
).toJSON() as DOMRect;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getLinkAtSelection() {
|
|
52
|
+
return editor.transact((tr) => {
|
|
53
|
+
const selection = tr.selection;
|
|
54
|
+
if (!selection.empty) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
return getMarkAtPos(selection.anchor, "link");
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
key: "linkToolbar",
|
|
63
|
+
|
|
64
|
+
getLinkAtSelection,
|
|
65
|
+
getLinkElementAtPos,
|
|
66
|
+
getMarkAtPos,
|
|
67
|
+
|
|
68
|
+
getLinkAtElement(element: HTMLElement) {
|
|
69
|
+
return editor.transact(() => {
|
|
70
|
+
const posAtElement = editor.prosemirrorView.posAtDOM(element, 0) + 1;
|
|
71
|
+
return getMarkAtPos(posAtElement, "link");
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
editLink(
|
|
76
|
+
url: string,
|
|
77
|
+
text: string,
|
|
78
|
+
position = editor.transact((tr) => tr.selection.anchor),
|
|
79
|
+
) {
|
|
80
|
+
editor.transact((tr) => {
|
|
81
|
+
const pmSchema = getPmSchema(tr);
|
|
82
|
+
const { range } = getMarkAtPos(position + 1, "link") || {
|
|
83
|
+
range: {
|
|
84
|
+
from: tr.selection.from,
|
|
85
|
+
to: tr.selection.to,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
if (!range) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
tr.insertText(text, range.from, range.to);
|
|
92
|
+
tr.addMark(
|
|
93
|
+
range.from,
|
|
94
|
+
range.from + text.length,
|
|
95
|
+
pmSchema.mark("link", { href: url }),
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
editor.prosemirrorView.focus();
|
|
99
|
+
},
|
|
100
|
+
deleteLink(position = editor.transact((tr) => tr.selection.anchor)) {
|
|
101
|
+
editor.transact((tr) => {
|
|
102
|
+
const pmSchema = getPmSchema(tr);
|
|
103
|
+
const { range } = getMarkAtPos(position + 1, "link") || {
|
|
104
|
+
range: {
|
|
105
|
+
from: tr.selection.from,
|
|
106
|
+
to: tr.selection.to,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
if (!range) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
tr.removeMark(range.from, range.to, pmSchema.marks["link"]).setMeta(
|
|
114
|
+
"preventAutolink",
|
|
115
|
+
true,
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
editor.prosemirrorView.focus();
|
|
119
|
+
},
|
|
120
|
+
} as const;
|
|
121
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Plugin, PluginKey, TextSelection } from "prosemirror-state";
|
|
2
|
+
import { createExtension } from "../../editor/BlockNoteExtension.js";
|
|
3
|
+
|
|
4
|
+
const PLUGIN_KEY = new PluginKey("node-selection-keyboard");
|
|
5
|
+
// By default, typing with a node selection active will cause ProseMirror to
|
|
6
|
+
// replace the node with one that contains editable content. This plugin blocks
|
|
7
|
+
// this behaviour without also blocking things like keyboard shortcuts:
|
|
8
|
+
//
|
|
9
|
+
// - Lets through key presses that do not include alphanumeric characters. This
|
|
10
|
+
// includes things like backspace/delete/home/end/etc.
|
|
11
|
+
// - Lets through any key presses that include ctrl/meta keys. These will be
|
|
12
|
+
// shortcuts of some kind like ctrl+C/mod+C.
|
|
13
|
+
// - Special case for Enter key which creates a new paragraph block below and
|
|
14
|
+
// sets the selection to it. This is just to bring the UX closer to Notion
|
|
15
|
+
//
|
|
16
|
+
// While a more elegant solution would probably process transactions instead of
|
|
17
|
+
// keystrokes, this brings us most of the way to Notion's UX without much added
|
|
18
|
+
// complexity.
|
|
19
|
+
export const NodeSelectionKeyboardExtension = createExtension(
|
|
20
|
+
() =>
|
|
21
|
+
({
|
|
22
|
+
key: "nodeSelectionKeyboard",
|
|
23
|
+
prosemirrorPlugins: [
|
|
24
|
+
new Plugin({
|
|
25
|
+
key: PLUGIN_KEY,
|
|
26
|
+
props: {
|
|
27
|
+
handleKeyDown: (view, event) => {
|
|
28
|
+
// Checks for node selection
|
|
29
|
+
if ("node" in view.state.selection) {
|
|
30
|
+
// Checks if key press uses ctrl/meta modifier
|
|
31
|
+
if (event.ctrlKey || event.metaKey) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
// Checks if key press is alphanumeric
|
|
35
|
+
if (event.key.length === 1) {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
// Checks if key press is Enter
|
|
41
|
+
if (
|
|
42
|
+
event.key === "Enter" &&
|
|
43
|
+
!event.shiftKey &&
|
|
44
|
+
!event.altKey &&
|
|
45
|
+
!event.ctrlKey &&
|
|
46
|
+
!event.metaKey
|
|
47
|
+
) {
|
|
48
|
+
const tr = view.state.tr;
|
|
49
|
+
view.dispatch(
|
|
50
|
+
tr
|
|
51
|
+
.insert(
|
|
52
|
+
view.state.tr.selection.$to.after(),
|
|
53
|
+
view.state.schema.nodes["paragraph"].createChecked(),
|
|
54
|
+
)
|
|
55
|
+
.setSelection(
|
|
56
|
+
new TextSelection(
|
|
57
|
+
tr.doc.resolve(
|
|
58
|
+
view.state.tr.selection.$to.after() + 1,
|
|
59
|
+
),
|
|
60
|
+
),
|
|
61
|
+
),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return false;
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
],
|
|
73
|
+
}) as const,
|
|
74
|
+
);
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Plugin, PluginKey } from "prosemirror-state";
|
|
2
|
+
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
3
|
+
import { v4 } from "uuid";
|
|
4
|
+
import {
|
|
5
|
+
createExtension,
|
|
6
|
+
ExtensionOptions,
|
|
7
|
+
} from "../../editor/BlockNoteExtension.js";
|
|
8
|
+
import { BlockNoteEditorOptions } from "../../editor/BlockNoteEditor.js";
|
|
9
|
+
|
|
10
|
+
const PLUGIN_KEY = new PluginKey(`blocknote-placeholder`);
|
|
11
|
+
|
|
12
|
+
export const PlaceholderExtension = createExtension(
|
|
13
|
+
({
|
|
14
|
+
editor,
|
|
15
|
+
options,
|
|
16
|
+
}: ExtensionOptions<
|
|
17
|
+
Pick<BlockNoteEditorOptions<any, any, any>, "placeholders">
|
|
18
|
+
>) => {
|
|
19
|
+
const placeholders = options.placeholders;
|
|
20
|
+
return {
|
|
21
|
+
key: "placeholder",
|
|
22
|
+
prosemirrorPlugins: [
|
|
23
|
+
new Plugin({
|
|
24
|
+
key: PLUGIN_KEY,
|
|
25
|
+
view: (view) => {
|
|
26
|
+
const uniqueEditorSelector = `placeholder-selector-${v4()}`;
|
|
27
|
+
view.dom.classList.add(uniqueEditorSelector);
|
|
28
|
+
const styleEl = document.createElement("style");
|
|
29
|
+
|
|
30
|
+
const nonce = editor._tiptapEditor.options.injectNonce;
|
|
31
|
+
if (nonce) {
|
|
32
|
+
styleEl.setAttribute("nonce", nonce);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (view.root instanceof window.ShadowRoot) {
|
|
36
|
+
view.root.append(styleEl);
|
|
37
|
+
} else {
|
|
38
|
+
view.root.head.appendChild(styleEl);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const styleSheet = styleEl.sheet!;
|
|
42
|
+
|
|
43
|
+
const getSelector = (additionalSelectors = "") =>
|
|
44
|
+
`.${uniqueEditorSelector} .bn-block-content${additionalSelectors} .bn-inline-content:has(> .ProseMirror-trailingBreak:only-child):before`;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
// FIXME: the names "default" and "emptyDocument" are hardcoded
|
|
48
|
+
const {
|
|
49
|
+
default: defaultPlaceholder,
|
|
50
|
+
emptyDocument: emptyPlaceholder,
|
|
51
|
+
...rest
|
|
52
|
+
} = placeholders || {};
|
|
53
|
+
|
|
54
|
+
// add block specific placeholders
|
|
55
|
+
for (const [blockType, placeholder] of Object.entries(rest)) {
|
|
56
|
+
const blockTypeSelector = `[data-content-type="${blockType}"]`;
|
|
57
|
+
|
|
58
|
+
styleSheet.insertRule(
|
|
59
|
+
`${getSelector(blockTypeSelector)} { content: ${JSON.stringify(
|
|
60
|
+
placeholder,
|
|
61
|
+
)}; }`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const onlyBlockSelector = `[data-is-only-empty-block]`;
|
|
66
|
+
const mustBeFocusedSelector = `[data-is-empty-and-focused]`;
|
|
67
|
+
|
|
68
|
+
// placeholder for when there's only one empty block
|
|
69
|
+
styleSheet.insertRule(
|
|
70
|
+
`${getSelector(onlyBlockSelector)} { content: ${JSON.stringify(
|
|
71
|
+
emptyPlaceholder,
|
|
72
|
+
)}; }`,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// placeholder for default blocks, only when the cursor is in the block (mustBeFocused)
|
|
76
|
+
styleSheet.insertRule(
|
|
77
|
+
`${getSelector(mustBeFocusedSelector)} { content: ${JSON.stringify(
|
|
78
|
+
defaultPlaceholder,
|
|
79
|
+
)}; }`,
|
|
80
|
+
);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
// eslint-disable-next-line no-console
|
|
83
|
+
console.warn(
|
|
84
|
+
`Failed to insert placeholder CSS rule - this is likely due to the browser not supporting certain CSS pseudo-element selectors (:has, :only-child:, or :before)`,
|
|
85
|
+
e,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
destroy: () => {
|
|
91
|
+
if (view.root instanceof window.ShadowRoot) {
|
|
92
|
+
view.root.removeChild(styleEl);
|
|
93
|
+
} else {
|
|
94
|
+
view.root.head.removeChild(styleEl);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
props: {
|
|
100
|
+
decorations: (state) => {
|
|
101
|
+
const { doc, selection } = state;
|
|
102
|
+
|
|
103
|
+
if (!editor.isEditable) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!selection.empty) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Don't show placeholder when the cursor is inside a code block
|
|
112
|
+
if (selection.$from.parent.type.spec.code) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const decs = [];
|
|
117
|
+
|
|
118
|
+
// decoration for when there's only one empty block
|
|
119
|
+
// positions are hardcoded for now
|
|
120
|
+
if (state.doc.content.size === 6) {
|
|
121
|
+
decs.push(
|
|
122
|
+
Decoration.node(2, 4, {
|
|
123
|
+
"data-is-only-empty-block": "true",
|
|
124
|
+
}),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const $pos = selection.$anchor;
|
|
129
|
+
const node = $pos.parent;
|
|
130
|
+
|
|
131
|
+
if (node.content.size === 0) {
|
|
132
|
+
const before = $pos.before();
|
|
133
|
+
|
|
134
|
+
decs.push(
|
|
135
|
+
Decoration.node(before, before + node.nodeSize, {
|
|
136
|
+
"data-is-empty-and-focused": "true",
|
|
137
|
+
}),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return DecorationSet.create(doc, decs);
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
],
|
|
146
|
+
} as const;
|
|
147
|
+
},
|
|
148
|
+
);
|
package/src/extensions/PreviousBlockType/{PreviousBlockTypePlugin.ts → PreviousBlockType.ts}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { findChildren } from "@tiptap/core";
|
|
2
2
|
import { Plugin, PluginKey } from "prosemirror-state";
|
|
3
3
|
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
4
|
-
import {
|
|
4
|
+
import { createExtension } from "../../editor/BlockNoteExtension.js";
|
|
5
5
|
|
|
6
6
|
const PLUGIN_KEY = new PluginKey(`previous-blocks`);
|
|
7
7
|
|
|
@@ -24,15 +24,11 @@ const nodeAttributes: Record<string, string> = {
|
|
|
24
24
|
*
|
|
25
25
|
* Solution: When attributes change on a node, this plugin sets a data-* attribute with the "previous" value. This way we can still use CSS transitions. (See block.module.css)
|
|
26
26
|
*/
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
constructor() {
|
|
33
|
-
super();
|
|
34
|
-
let timeout: ReturnType<typeof setTimeout>;
|
|
35
|
-
this.addProsemirrorPlugin(
|
|
27
|
+
export const PreviousBlockTypeExtension = createExtension(() => {
|
|
28
|
+
let timeout: ReturnType<typeof setTimeout>;
|
|
29
|
+
return {
|
|
30
|
+
key: "previousBlockType",
|
|
31
|
+
prosemirrorPlugins: [
|
|
36
32
|
new Plugin({
|
|
37
33
|
key: PLUGIN_KEY,
|
|
38
34
|
view(_editorView) {
|
|
@@ -207,6 +203,6 @@ export class PreviousBlockTypePlugin extends BlockNoteExtension {
|
|
|
207
203
|
},
|
|
208
204
|
},
|
|
209
205
|
}),
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
}
|
|
206
|
+
],
|
|
207
|
+
} as const;
|
|
208
|
+
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Plugin, PluginKey } from "prosemirror-state";
|
|
2
2
|
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
createExtension,
|
|
5
|
+
createStore,
|
|
6
|
+
} from "../../editor/BlockNoteExtension.js";
|
|
5
7
|
|
|
6
8
|
const PLUGIN_KEY = new PluginKey(`blocknote-show-selection`);
|
|
7
9
|
|
|
@@ -10,48 +12,40 @@ const PLUGIN_KEY = new PluginKey(`blocknote-show-selection`);
|
|
|
10
12
|
* This can be used to highlight the current selection in the UI even when the
|
|
11
13
|
* text editor is not focused.
|
|
12
14
|
*/
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
export const ShowSelectionExtension = createExtension(({ editor }) => {
|
|
16
|
+
const store = createStore(
|
|
17
|
+
{ enabled: false },
|
|
18
|
+
{
|
|
19
|
+
onUpdate() {
|
|
20
|
+
editor.transact((tr) => tr.setMeta(PLUGIN_KEY, {}));
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
return {
|
|
25
|
+
key: "showSelection",
|
|
26
|
+
store,
|
|
27
|
+
prosemirrorPlugins: [
|
|
23
28
|
new Plugin({
|
|
24
29
|
key: PLUGIN_KEY,
|
|
25
30
|
props: {
|
|
26
31
|
decorations: (state) => {
|
|
27
32
|
const { doc, selection } = state;
|
|
28
|
-
|
|
29
|
-
if (!this.enabled) {
|
|
33
|
+
if (!store.state.enabled) {
|
|
30
34
|
return DecorationSet.empty;
|
|
31
35
|
}
|
|
32
|
-
|
|
33
36
|
const dec = Decoration.inline(selection.from, selection.to, {
|
|
34
37
|
"data-show-selection": "true",
|
|
35
38
|
});
|
|
36
|
-
|
|
37
39
|
return DecorationSet.create(doc, [dec]);
|
|
38
40
|
},
|
|
39
41
|
},
|
|
40
42
|
}),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
this.editor.transact((tr) => tr.setMeta(PLUGIN_KEY, {}));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
public getEnabled() {
|
|
55
|
-
return this.enabled;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
43
|
+
],
|
|
44
|
+
/**
|
|
45
|
+
* Show or hide the selection decoration
|
|
46
|
+
*/
|
|
47
|
+
showSelection(shouldShow: boolean) {
|
|
48
|
+
store.setState({ enabled: shouldShow });
|
|
49
|
+
},
|
|
50
|
+
} as const;
|
|
51
|
+
});
|
|
@@ -10,7 +10,10 @@ import { EditorView } from "@tiptap/pm/view";
|
|
|
10
10
|
|
|
11
11
|
import { Block } from "../../blocks/defaultBlocks.js";
|
|
12
12
|
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
createExtension,
|
|
15
|
+
createStore,
|
|
16
|
+
} from "../../editor/BlockNoteExtension.js";
|
|
14
17
|
import { UiElementPosition } from "../../extensions-shared/UiElementPosition.js";
|
|
15
18
|
import {
|
|
16
19
|
BlockSchema,
|
|
@@ -184,11 +187,6 @@ export class SideMenuView<
|
|
|
184
187
|
this.onKeyDown as EventListener,
|
|
185
188
|
true,
|
|
186
189
|
);
|
|
187
|
-
|
|
188
|
-
// Setting capture=true ensures that any parent container of the editor that
|
|
189
|
-
// gets scrolled will trigger the scroll event. Scroll events do not bubble
|
|
190
|
-
// and so won't propagate to the document by default.
|
|
191
|
-
pmView.root.addEventListener("scroll", this.onScroll, true);
|
|
192
190
|
}
|
|
193
191
|
|
|
194
192
|
updateState = (state: SideMenuState<BSchema, I, S>) => {
|
|
@@ -621,14 +619,6 @@ export class SideMenuView<
|
|
|
621
619
|
this.pmView.dom.dispatchEvent(evt);
|
|
622
620
|
}
|
|
623
621
|
|
|
624
|
-
onScroll = () => {
|
|
625
|
-
if (this.state?.show) {
|
|
626
|
-
this.state.referencePos = this.hoveredBlock!.getBoundingClientRect();
|
|
627
|
-
this.emitUpdate(this.state);
|
|
628
|
-
}
|
|
629
|
-
this.updateStateFromMousePos();
|
|
630
|
-
};
|
|
631
|
-
|
|
632
622
|
// Needed in cases where the editor state updates without the mouse cursor
|
|
633
623
|
// moving, as some state updates can require a side menu update. For example,
|
|
634
624
|
// adding a button to the side menu which removes the block can cause the
|
|
@@ -676,89 +666,79 @@ export class SideMenuView<
|
|
|
676
666
|
this.onKeyDown as EventListener,
|
|
677
667
|
true,
|
|
678
668
|
);
|
|
679
|
-
this.pmView.root.removeEventListener("scroll", this.onScroll, true);
|
|
680
669
|
}
|
|
681
670
|
}
|
|
682
671
|
|
|
683
672
|
export const sideMenuPluginKey = new PluginKey("SideMenuPlugin");
|
|
684
673
|
|
|
685
|
-
export
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
public static key() {
|
|
691
|
-
return "sideMenu";
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
public view: SideMenuView<BSchema, I, S> | undefined;
|
|
674
|
+
export const SideMenuExtension = createExtension(({ editor }) => {
|
|
675
|
+
let view: SideMenuView<any, any, any> | undefined;
|
|
676
|
+
const store = createStore<SideMenuState<any, any, any> | undefined>(
|
|
677
|
+
undefined,
|
|
678
|
+
);
|
|
695
679
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
680
|
+
return {
|
|
681
|
+
key: "sideMenu",
|
|
682
|
+
store,
|
|
683
|
+
prosemirrorPlugins: [
|
|
699
684
|
new Plugin({
|
|
700
685
|
key: sideMenuPluginKey,
|
|
701
686
|
view: (editorView) => {
|
|
702
|
-
|
|
703
|
-
|
|
687
|
+
view = new SideMenuView(editor, editorView, (state) => {
|
|
688
|
+
// TODO: Without spreading the state, in some cases like toggling
|
|
689
|
+
// `show`, this doesn't trigger an update.
|
|
690
|
+
store.setState({ ...state });
|
|
704
691
|
});
|
|
705
|
-
return
|
|
692
|
+
return view;
|
|
706
693
|
},
|
|
707
694
|
}),
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
clientY: number;
|
|
695
|
+
],
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Handles drag & drop events for blocks.
|
|
699
|
+
*/
|
|
700
|
+
blockDragStart(
|
|
701
|
+
event: { dataTransfer: DataTransfer | null; clientY: number },
|
|
702
|
+
block: Block<any, any, any>,
|
|
703
|
+
) {
|
|
704
|
+
if (view) {
|
|
705
|
+
view.isDragOrigin = true;
|
|
706
|
+
}
|
|
707
|
+
dragStart(event, block, editor);
|
|
722
708
|
},
|
|
723
|
-
block: Block<BSchema, I, S>,
|
|
724
|
-
) => {
|
|
725
|
-
if (this.view) {
|
|
726
|
-
this.view.isDragOrigin = true;
|
|
727
|
-
}
|
|
728
709
|
|
|
729
|
-
|
|
730
|
-
|
|
710
|
+
/**
|
|
711
|
+
* Handles drag & drop events for blocks.
|
|
712
|
+
*/
|
|
713
|
+
blockDragEnd() {
|
|
714
|
+
unsetDragImage(editor.prosemirrorView.root);
|
|
715
|
+
if (view) {
|
|
716
|
+
view.isDragOrigin = false;
|
|
717
|
+
}
|
|
731
718
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
*/
|
|
735
|
-
blockDragEnd = () => {
|
|
736
|
-
unsetDragImage(this.editor.prosemirrorView.root);
|
|
719
|
+
editor.blur();
|
|
720
|
+
},
|
|
737
721
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
722
|
+
/**
|
|
723
|
+
* Freezes the side menu. When frozen, the side menu will stay
|
|
724
|
+
* attached to the same block regardless of which block is hovered by the
|
|
725
|
+
* mouse cursor.
|
|
726
|
+
*/
|
|
727
|
+
freezeMenu() {
|
|
728
|
+
view!.menuFrozen = true;
|
|
729
|
+
view!.state!.show = true;
|
|
730
|
+
view!.emitUpdate(view!.state!);
|
|
731
|
+
},
|
|
741
732
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
/**
|
|
755
|
-
* Unfreezes the side menu. When frozen, the side menu will stay
|
|
756
|
-
* attached to the same block regardless of which block is hovered by the
|
|
757
|
-
* mouse cursor.
|
|
758
|
-
*/
|
|
759
|
-
unfreezeMenu = () => {
|
|
760
|
-
this.view!.menuFrozen = false;
|
|
761
|
-
this.view!.state!.show = false;
|
|
762
|
-
this.view!.emitUpdate(this.view!.state!);
|
|
763
|
-
};
|
|
764
|
-
}
|
|
733
|
+
/**
|
|
734
|
+
* Unfreezes the side menu. When frozen, the side menu will stay
|
|
735
|
+
* attached to the same block regardless of which block is hovered by the
|
|
736
|
+
* mouse cursor.
|
|
737
|
+
*/
|
|
738
|
+
unfreezeMenu() {
|
|
739
|
+
view!.menuFrozen = false;
|
|
740
|
+
view!.state!.show = false;
|
|
741
|
+
view!.emitUpdate(view!.state!);
|
|
742
|
+
},
|
|
743
|
+
} as const;
|
|
744
|
+
});
|