@blocknote/core 0.16.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blocknote.js +3292 -2755
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +6 -6
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +5 -2
- package/src/api/blockManipulation/commands/insertBlocks/__snapshots__/insertBlocks.test.ts.snap +3087 -0
- package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.test.ts +132 -0
- package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +71 -0
- package/src/api/blockManipulation/commands/mergeBlocks/__snapshots__/mergeBlocks.test.ts.snap +2276 -0
- package/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts +131 -0
- package/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts +103 -0
- package/src/api/blockManipulation/commands/moveBlock/__snapshots__/moveBlock.test.ts.snap +3767 -0
- package/src/api/blockManipulation/commands/moveBlock/moveBlock.test.ts +192 -0
- package/src/api/blockManipulation/commands/moveBlock/moveBlock.ts +178 -0
- package/src/api/blockManipulation/commands/removeBlocks/__snapshots__/removeBlocks.test.ts.snap +1136 -0
- package/src/api/blockManipulation/commands/removeBlocks/removeBlocks.test.ts +34 -0
- package/src/api/blockManipulation/commands/removeBlocks/removeBlocks.ts +100 -0
- package/src/api/blockManipulation/commands/replaceBlocks/__snapshots__/replaceBlocks.test.ts.snap +4931 -0
- package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.test.ts +222 -0
- package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts +70 -0
- package/src/api/blockManipulation/commands/splitBlock/__snapshots__/splitBlock.test.ts.snap +2924 -0
- package/src/api/blockManipulation/commands/splitBlock/splitBlock.test.ts +136 -0
- package/src/api/blockManipulation/commands/splitBlock/splitBlock.ts +48 -0
- package/src/api/blockManipulation/commands/updateBlock/__snapshots__/updateBlock.test.ts.snap +8376 -0
- package/src/api/blockManipulation/commands/updateBlock/updateBlock.test.ts +300 -0
- package/src/api/blockManipulation/commands/updateBlock/updateBlock.ts +199 -0
- package/src/api/blockManipulation/insertContentAt.ts +96 -0
- package/src/api/blockManipulation/selections/textCursorPosition/__snapshots__/textCursorPosition.test.ts.snap +316 -0
- package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.test.ts +53 -0
- package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.ts +130 -0
- package/src/api/blockManipulation/setupTestEnv.ts +179 -0
- package/src/api/clipboard/__snapshots__/tableAllCells.html +1 -1
- package/src/api/clipboard/clipboard.test.ts +5 -6
- package/src/api/clipboard/fromClipboard/fileDropExtension.ts +8 -4
- package/src/api/clipboard/fromClipboard/handleFileInsertion.ts +11 -6
- package/src/api/clipboard/fromClipboard/pasteExtension.ts +8 -4
- package/src/api/clipboard/toClipboard/copyExtension.ts +113 -61
- package/src/api/exporters/html/__snapshots__/complex/misc/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/lists/basic/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/lists/nested/external.html +1 -1
- package/src/api/exporters/html/externalHTMLExporter.ts +42 -94
- package/src/api/exporters/html/htmlConversion.test.ts +19 -13
- package/src/api/exporters/html/internalHTMLSerializer.ts +21 -72
- package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +263 -0
- package/src/api/exporters/html/util/serializeBlocksInternalHTML.ts +158 -0
- package/src/api/exporters/markdown/markdownExporter.test.ts +10 -10
- package/src/api/exporters/markdown/markdownExporter.ts +11 -7
- package/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts +2 -2
- package/src/api/getBlockInfoFromPos.ts +172 -90
- package/src/api/nodeConversions/blockToNode.ts +257 -0
- package/src/api/nodeConversions/fragmentToBlocks.ts +60 -0
- package/src/api/nodeConversions/nodeConversions.test.ts +9 -8
- package/src/api/nodeConversions/{nodeConversions.ts → nodeToBlock.ts} +20 -262
- package/src/api/parsers/html/parseHTML.test.ts +2 -2
- package/src/api/parsers/html/parseHTML.ts +8 -4
- package/src/api/parsers/html/util/nestedLists.test.ts +2 -2
- package/src/api/parsers/markdown/parseMarkdown.test.ts +2 -2
- package/src/api/parsers/markdown/parseMarkdown.ts +8 -4
- package/src/api/testUtil/cases/customBlocks.ts +11 -11
- package/src/api/testUtil/cases/customInlineContent.ts +6 -6
- package/src/api/testUtil/cases/customStyles.ts +6 -6
- package/src/api/testUtil/cases/defaultSchema.ts +4 -4
- package/src/api/testUtil/index.ts +6 -6
- package/src/api/testUtil/partialBlockTestUtil.ts +5 -5
- package/src/blocks/AudioBlockContent/AudioBlockContent.ts +5 -5
- package/src/blocks/FileBlockContent/FileBlockContent.ts +4 -4
- package/src/blocks/FileBlockContent/fileBlockHelpers.ts +2 -2
- package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +61 -39
- package/src/blocks/ImageBlockContent/ImageBlockContent.ts +5 -5
- package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +30 -18
- package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +67 -33
- package/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts +23 -19
- package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts +22 -24
- package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +31 -19
- package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +16 -11
- package/src/blocks/TableBlockContent/TableBlockContent.ts +4 -4
- package/src/blocks/VideoBlockContent/VideoBlockContent.ts +5 -5
- package/src/blocks/defaultBlockHelpers.ts +4 -4
- package/src/blocks/defaultBlockTypeGuards.ts +5 -5
- package/src/blocks/defaultBlocks.ts +13 -13
- package/src/blocks/defaultProps.ts +1 -1
- package/src/editor/BlockNoteEditor.test.ts +14 -7
- package/src/editor/BlockNoteEditor.ts +82 -149
- package/src/editor/BlockNoteExtensions.ts +15 -11
- package/src/editor/BlockNoteSchema.ts +7 -7
- package/src/editor/BlockNoteTipTapEditor.ts +5 -3
- package/src/editor/cursorPositionTypes.ts +7 -2
- package/src/editor/selectionTypes.ts +6 -2
- package/src/extensions/BackgroundColor/BackgroundColorExtension.ts +1 -1
- package/src/extensions/BackgroundColor/BackgroundColorMark.ts +1 -1
- package/src/extensions/FilePanel/FilePanelPlugin.ts +4 -4
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +8 -4
- package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +334 -0
- package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +9 -4
- package/src/extensions/{NonEditableBlocks/NonEditableBlockPlugin.ts → NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts} +2 -2
- package/src/extensions/Placeholder/PlaceholderPlugin.ts +1 -1
- package/src/extensions/SideMenu/SideMenuPlugin.ts +72 -401
- package/src/extensions/SideMenu/dragging.ts +251 -0
- package/src/extensions/SuggestionMenu/DefaultSuggestionItem.ts +1 -1
- package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +8 -4
- package/src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts +8 -4
- package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +19 -15
- package/src/extensions/TableHandles/TableHandlesPlugin.ts +11 -7
- package/src/extensions/TextColor/TextColorExtension.ts +1 -1
- package/src/extensions/TextColor/TextColorMark.ts +1 -1
- package/src/i18n/dictionary.ts +1 -1
- package/src/i18n/locales/ar.ts +1 -1
- package/src/i18n/locales/fr.ts +1 -1
- package/src/i18n/locales/hr.ts +308 -0
- package/src/i18n/locales/index.ts +15 -14
- package/src/i18n/locales/is.ts +1 -1
- package/src/i18n/locales/ja.ts +1 -1
- package/src/i18n/locales/ko.ts +1 -1
- package/src/i18n/locales/nl.ts +1 -1
- package/src/i18n/locales/pl.ts +1 -1
- package/src/i18n/locales/pt.ts +1 -1
- package/src/i18n/locales/ru.ts +1 -1
- package/src/i18n/locales/vi.ts +1 -1
- package/src/i18n/locales/zh.ts +1 -1
- package/src/index.ts +45 -44
- package/src/pm-nodes/BlockContainer.ts +3 -647
- package/src/pm-nodes/BlockGroup.ts +2 -2
- package/src/pm-nodes/index.ts +3 -3
- package/src/schema/blocks/createSpec.ts +8 -7
- package/src/schema/blocks/internal.ts +9 -9
- package/src/schema/blocks/types.ts +4 -4
- package/src/schema/index.ts +10 -10
- package/src/schema/inlineContent/createSpec.ts +9 -10
- package/src/schema/inlineContent/internal.ts +3 -3
- package/src/schema/inlineContent/types.ts +2 -2
- package/src/schema/styles/createSpec.ts +4 -3
- package/src/schema/styles/internal.ts +1 -1
- package/types/src/api/blockManipulation/commands/insertBlocks/insertBlocks.d.ts +4 -0
- package/types/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.d.ts +7 -0
- package/types/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.d.ts +1 -0
- package/types/src/api/blockManipulation/commands/moveBlock/moveBlock.d.ts +5 -0
- package/types/src/api/blockManipulation/commands/moveBlock/moveBlock.test.d.ts +1 -0
- package/types/src/api/blockManipulation/commands/removeBlocks/removeBlocks.d.ts +7 -0
- package/types/src/api/blockManipulation/commands/removeBlocks/removeBlocks.test.d.ts +1 -0
- package/types/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.d.ts +7 -0
- package/types/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.test.d.ts +1 -0
- package/types/src/api/blockManipulation/commands/splitBlock/splitBlock.d.ts +5 -0
- package/types/src/api/blockManipulation/commands/splitBlock/splitBlock.test.d.ts +1 -0
- package/types/src/api/blockManipulation/commands/updateBlock/updateBlock.d.ts +11 -0
- package/types/src/api/blockManipulation/commands/updateBlock/updateBlock.test.d.ts +1 -0
- package/types/src/api/blockManipulation/insertContentAt.d.ts +6 -0
- package/types/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.d.ts +5 -0
- package/types/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.test.d.ts +1 -0
- package/types/src/api/blockManipulation/setupTestEnv.d.ts +492 -0
- package/types/src/api/clipboard/fromClipboard/fileDropExtension.d.ts +3 -3
- package/types/src/api/clipboard/fromClipboard/handleFileInsertion.d.ts +1 -1
- package/types/src/api/clipboard/fromClipboard/pasteExtension.d.ts +2 -2
- package/types/src/api/clipboard/toClipboard/copyExtension.d.ts +5 -5
- package/types/src/api/exporters/html/externalHTMLExporter.d.ts +7 -9
- package/types/src/api/exporters/html/internalHTMLSerializer.d.ts +6 -10
- package/types/src/api/exporters/html/util/serializeBlocksExternalHTML.d.ts +10 -0
- package/types/src/api/exporters/html/util/serializeBlocksInternalHTML.d.ts +11 -0
- package/types/src/api/exporters/markdown/markdownExporter.d.ts +3 -3
- package/types/src/api/getBlockInfoFromPos.d.ts +63 -20
- package/types/src/api/nodeConversions/blockToNode.d.ts +15 -0
- package/types/src/api/nodeConversions/fragmentToBlocks.d.ts +7 -0
- package/types/src/api/nodeConversions/nodeToBlock.d.ts +16 -0
- package/types/src/api/parsers/html/parseHTML.d.ts +2 -2
- package/types/src/api/parsers/markdown/parseMarkdown.d.ts +2 -2
- package/types/src/api/testUtil/cases/customBlocks.d.ts +39 -39
- package/types/src/api/testUtil/cases/customInlineContent.d.ts +35 -35
- package/types/src/api/testUtil/cases/customStyles.d.ts +35 -35
- package/types/src/api/testUtil/cases/defaultSchema.d.ts +2 -2
- package/types/src/api/testUtil/index.d.ts +6 -6
- package/types/src/api/testUtil/partialBlockTestUtil.d.ts +4 -4
- package/types/src/blocks/AudioBlockContent/AudioBlockContent.d.ts +4 -4
- package/types/src/blocks/FileBlockContent/FileBlockContent.d.ts +4 -4
- package/types/src/blocks/FileBlockContent/fileBlockHelpers.d.ts +2 -2
- package/types/src/blocks/HeadingBlockContent/HeadingBlockContent.d.ts +2 -2
- package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +4 -4
- package/types/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +2 -2
- package/types/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.d.ts +2 -2
- package/types/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.d.ts +2 -2
- package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +2 -2
- package/types/src/blocks/ParagraphBlockContent/ParagraphBlockContent.d.ts +2 -2
- package/types/src/blocks/TableBlockContent/TableBlockContent.d.ts +2 -2
- package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +4 -4
- package/types/src/blocks/defaultBlockHelpers.d.ts +3 -3
- package/types/src/blocks/defaultBlockTypeGuards.d.ts +4 -4
- package/types/src/blocks/defaultBlocks.d.ts +38 -38
- package/types/src/blocks/defaultProps.d.ts +1 -1
- package/types/src/editor/BlockNoteEditor.d.ts +28 -16
- package/types/src/editor/BlockNoteExtensions.d.ts +3 -3
- package/types/src/editor/BlockNoteSchema.d.ts +4 -4
- package/types/src/editor/BlockNoteTipTapEditor.d.ts +2 -2
- package/types/src/editor/cursorPositionTypes.d.ts +3 -2
- package/types/src/editor/selectionTypes.d.ts +2 -2
- package/types/src/extensions/BackgroundColor/BackgroundColorMark.d.ts +1 -1
- package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +4 -4
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +4 -4
- package/types/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.d.ts +5 -0
- package/types/src/extensions/LinkToolbar/LinkToolbarPlugin.d.ts +4 -4
- package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.d.ts +2 -0
- package/types/src/extensions/Placeholder/PlaceholderPlugin.d.ts +1 -1
- package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +12 -28
- package/types/src/extensions/SideMenu/dragging.d.ts +17 -0
- package/types/src/extensions/SuggestionMenu/DefaultSuggestionItem.d.ts +1 -1
- package/types/src/extensions/SuggestionMenu/SuggestionPlugin.d.ts +4 -4
- package/types/src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.d.ts +3 -3
- package/types/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.d.ts +4 -4
- package/types/src/extensions/TableHandles/TableHandlesPlugin.d.ts +4 -4
- package/types/src/extensions/TextColor/TextColorMark.d.ts +1 -1
- package/types/src/i18n/dictionary.d.ts +1 -1
- package/types/src/i18n/locales/ar.d.ts +1 -1
- package/types/src/i18n/locales/fr.d.ts +1 -1
- package/types/src/i18n/locales/hr.d.ts +239 -0
- package/types/src/i18n/locales/index.d.ts +15 -14
- package/types/src/i18n/locales/is.d.ts +1 -1
- package/types/src/i18n/locales/ja.d.ts +1 -1
- package/types/src/i18n/locales/ko.d.ts +1 -1
- package/types/src/i18n/locales/nl.d.ts +1 -1
- package/types/src/i18n/locales/pl.d.ts +1 -1
- package/types/src/i18n/locales/pt.d.ts +1 -1
- package/types/src/i18n/locales/ru.d.ts +1 -1
- package/types/src/i18n/locales/vi.d.ts +1 -1
- package/types/src/i18n/locales/zh.d.ts +1 -1
- package/types/src/index.d.ts +45 -44
- package/types/src/pm-nodes/BlockContainer.d.ts +2 -16
- package/types/src/pm-nodes/BlockGroup.d.ts +1 -1
- package/types/src/pm-nodes/index.d.ts +3 -3
- package/types/src/schema/blocks/createSpec.d.ts +5 -5
- package/types/src/schema/blocks/internal.d.ts +5 -5
- package/types/src/schema/blocks/types.d.ts +4 -4
- package/types/src/schema/index.d.ts +10 -10
- package/types/src/schema/inlineContent/createSpec.d.ts +3 -3
- package/types/src/schema/inlineContent/internal.d.ts +2 -2
- package/types/src/schema/inlineContent/types.d.ts +2 -2
- package/types/src/schema/styles/createSpec.d.ts +1 -1
- package/types/src/schema/styles/internal.d.ts +1 -1
- package/src/api/blockManipulation/__snapshots__/blockManipulation.test.ts.snap +0 -714
- package/src/api/blockManipulation/blockManipulation.test.ts +0 -292
- package/src/api/blockManipulation/blockManipulation.ts +0 -350
- package/src/api/exporters/html/util/sharedHTMLConversion.ts +0 -130
- package/src/api/exporters/html/util/simplifyBlocksRehypePlugin.ts +0 -218
- package/src/api/getCurrentBlockContentType.ts +0 -14
- package/types/src/api/blockManipulation/blockManipulation.d.ts +0 -14
- package/types/src/api/exporters/html/util/sharedHTMLConversion.d.ts +0 -9
- package/types/src/api/exporters/html/util/simplifyBlocksRehypePlugin.d.ts +0 -16
- package/types/src/api/getCurrentBlockContentType.d.ts +0 -2
- package/types/src/api/nodeConversions/nodeConversions.d.ts +0 -24
- package/types/src/extensions/NonEditableBlocks/NonEditableBlockPlugin.d.ts +0 -2
- /package/types/src/api/blockManipulation/{blockManipulation.test.d.ts → commands/insertBlocks/insertBlocks.test.d.ts} +0 -0
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { EditorOptions, createDocument } from "@tiptap/core";
|
|
2
2
|
// import "./blocknote.css";
|
|
3
3
|
import { Editor as TiptapEditor } from "@tiptap/core";
|
|
4
|
+
|
|
4
5
|
import { Node } from "@tiptap/pm/model";
|
|
6
|
+
|
|
5
7
|
import { EditorView } from "@tiptap/pm/view";
|
|
6
8
|
|
|
7
9
|
import { EditorState, Transaction } from "@tiptap/pm/state";
|
|
8
|
-
import { blockToNode } from "../api/nodeConversions/
|
|
9
|
-
import { PartialBlock } from "../blocks/defaultBlocks";
|
|
10
|
-
import { StyleSchema } from "../schema";
|
|
10
|
+
import { blockToNode } from "../api/nodeConversions/blockToNode.js";
|
|
11
|
+
import { PartialBlock } from "../blocks/defaultBlocks.js";
|
|
12
|
+
import { StyleSchema } from "../schema/index.js";
|
|
11
13
|
|
|
12
14
|
export type BlockNoteTipTapEditorOptions = Partial<
|
|
13
15
|
Omit<EditorOptions, "content">
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { Block } from "../blocks/defaultBlocks";
|
|
2
|
-
import {
|
|
1
|
+
import { Block } from "../blocks/defaultBlocks.js";
|
|
2
|
+
import {
|
|
3
|
+
BlockSchema,
|
|
4
|
+
InlineContentSchema,
|
|
5
|
+
StyleSchema,
|
|
6
|
+
} from "../schema/index.js";
|
|
3
7
|
|
|
4
8
|
export type TextCursorPosition<
|
|
5
9
|
BSchema extends BlockSchema,
|
|
@@ -9,4 +13,5 @@ export type TextCursorPosition<
|
|
|
9
13
|
block: Block<BSchema, I, S>;
|
|
10
14
|
prevBlock: Block<BSchema, I, S> | undefined;
|
|
11
15
|
nextBlock: Block<BSchema, I, S> | undefined;
|
|
16
|
+
parentBlock: Block<BSchema, I, S> | undefined;
|
|
12
17
|
};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { Block } from "../blocks/defaultBlocks";
|
|
2
|
-
import {
|
|
1
|
+
import { Block } from "../blocks/defaultBlocks.js";
|
|
2
|
+
import {
|
|
3
|
+
BlockSchema,
|
|
4
|
+
InlineContentSchema,
|
|
5
|
+
StyleSchema,
|
|
6
|
+
} from "../schema/index.js";
|
|
3
7
|
|
|
4
8
|
export type Selection<
|
|
5
9
|
BSchema extends BlockSchema,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { EditorState, Plugin, PluginKey, PluginView } from "prosemirror-state";
|
|
2
2
|
import { EditorView } from "prosemirror-view";
|
|
3
3
|
|
|
4
|
-
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
|
|
5
|
-
import { UiElementPosition } from "../../extensions-shared/UiElementPosition";
|
|
4
|
+
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
|
|
5
|
+
import { UiElementPosition } from "../../extensions-shared/UiElementPosition.js";
|
|
6
6
|
import type {
|
|
7
7
|
BlockFromConfig,
|
|
8
8
|
FileBlockConfig,
|
|
9
9
|
InlineContentSchema,
|
|
10
10
|
StyleSchema,
|
|
11
|
-
} from "../../schema";
|
|
12
|
-
import { EventEmitter } from "../../util/EventEmitter";
|
|
11
|
+
} from "../../schema/index.js";
|
|
12
|
+
import { EventEmitter } from "../../util/EventEmitter.js";
|
|
13
13
|
|
|
14
14
|
export type FilePanelState<
|
|
15
15
|
I extends InlineContentSchema,
|
|
@@ -2,10 +2,14 @@ import { isNodeSelection, isTextSelection, posToDOMRect } from "@tiptap/core";
|
|
|
2
2
|
import { EditorState, Plugin, PluginKey, PluginView } from "prosemirror-state";
|
|
3
3
|
import { EditorView } from "prosemirror-view";
|
|
4
4
|
|
|
5
|
-
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
|
|
6
|
-
import { UiElementPosition } from "../../extensions-shared/UiElementPosition";
|
|
7
|
-
import {
|
|
8
|
-
|
|
5
|
+
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
|
|
6
|
+
import { UiElementPosition } from "../../extensions-shared/UiElementPosition.js";
|
|
7
|
+
import {
|
|
8
|
+
BlockSchema,
|
|
9
|
+
InlineContentSchema,
|
|
10
|
+
StyleSchema,
|
|
11
|
+
} from "../../schema/index.js";
|
|
12
|
+
import { EventEmitter } from "../../util/EventEmitter.js";
|
|
9
13
|
|
|
10
14
|
export type FormattingToolbarState = UiElementPosition;
|
|
11
15
|
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { Extension } from "@tiptap/core";
|
|
2
|
+
|
|
3
|
+
import { TextSelection } from "prosemirror-state";
|
|
4
|
+
import {
|
|
5
|
+
getPrevBlockPos,
|
|
6
|
+
mergeBlocksCommand,
|
|
7
|
+
} from "../../api/blockManipulation/commands/mergeBlocks/mergeBlocks.js";
|
|
8
|
+
import { splitBlockCommand } from "../../api/blockManipulation/commands/splitBlock/splitBlock.js";
|
|
9
|
+
import { updateBlockCommand } from "../../api/blockManipulation/commands/updateBlock/updateBlock.js";
|
|
10
|
+
import {
|
|
11
|
+
getBlockInfoFromResolvedPos,
|
|
12
|
+
getBlockInfoFromSelection,
|
|
13
|
+
} from "../../api/getBlockInfoFromPos.js";
|
|
14
|
+
import { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
|
|
15
|
+
|
|
16
|
+
export const KeyboardShortcutsExtension = Extension.create<{
|
|
17
|
+
editor: BlockNoteEditor<any, any, any>;
|
|
18
|
+
}>({
|
|
19
|
+
priority: 50,
|
|
20
|
+
|
|
21
|
+
// TODO: The shortcuts need a refactor. Do we want to use a command priority
|
|
22
|
+
// design as there is now, or clump the logic into a single function?
|
|
23
|
+
addKeyboardShortcuts() {
|
|
24
|
+
// handleBackspace is partially adapted from https://github.com/ueberdosis/tiptap/blob/ed56337470efb4fd277128ab7ef792b37cfae992/packages/core/src/extensions/keymap.ts
|
|
25
|
+
const handleBackspace = () =>
|
|
26
|
+
this.editor.commands.first(({ chain, commands }) => [
|
|
27
|
+
// Deletes the selection if it's not empty.
|
|
28
|
+
() => commands.deleteSelection(),
|
|
29
|
+
// Undoes an input rule if one was triggered in the last editor state change.
|
|
30
|
+
() => commands.undoInputRule(),
|
|
31
|
+
// Reverts block content type to a paragraph if the selection is at the start of the block.
|
|
32
|
+
() =>
|
|
33
|
+
commands.command(({ state }) => {
|
|
34
|
+
const blockInfo = getBlockInfoFromSelection(state);
|
|
35
|
+
|
|
36
|
+
const selectionAtBlockStart =
|
|
37
|
+
state.selection.from === blockInfo.blockContent.beforePos + 1;
|
|
38
|
+
const isParagraph =
|
|
39
|
+
blockInfo.blockContent.node.type.name === "paragraph";
|
|
40
|
+
|
|
41
|
+
if (selectionAtBlockStart && !isParagraph) {
|
|
42
|
+
return commands.command(
|
|
43
|
+
updateBlockCommand(
|
|
44
|
+
this.options.editor,
|
|
45
|
+
blockInfo.blockContainer.beforePos,
|
|
46
|
+
{
|
|
47
|
+
type: "paragraph",
|
|
48
|
+
props: {},
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return false;
|
|
55
|
+
}),
|
|
56
|
+
// Removes a level of nesting if the block is indented if the selection is at the start of the block.
|
|
57
|
+
() =>
|
|
58
|
+
commands.command(({ state }) => {
|
|
59
|
+
const { blockContent } = getBlockInfoFromSelection(state);
|
|
60
|
+
|
|
61
|
+
const selectionAtBlockStart =
|
|
62
|
+
state.selection.from === blockContent.beforePos + 1;
|
|
63
|
+
|
|
64
|
+
if (selectionAtBlockStart) {
|
|
65
|
+
return commands.liftListItem("blockContainer");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return false;
|
|
69
|
+
}),
|
|
70
|
+
// Merges block with the previous one if it isn't indented, isn't the
|
|
71
|
+
// first block in the doc, and the selection is at the start of the
|
|
72
|
+
// block. The target block for merging must contain inline content.
|
|
73
|
+
() =>
|
|
74
|
+
commands.command(({ state }) => {
|
|
75
|
+
const { blockContainer, blockContent } =
|
|
76
|
+
getBlockInfoFromSelection(state);
|
|
77
|
+
|
|
78
|
+
const { depth } = state.doc.resolve(blockContainer.beforePos);
|
|
79
|
+
|
|
80
|
+
const selectionAtBlockStart =
|
|
81
|
+
state.selection.from === blockContent.beforePos + 1;
|
|
82
|
+
const selectionEmpty = state.selection.empty;
|
|
83
|
+
const blockAtDocStart = blockContainer.beforePos === 1;
|
|
84
|
+
|
|
85
|
+
const posBetweenBlocks = blockContainer.beforePos;
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
!blockAtDocStart &&
|
|
89
|
+
selectionAtBlockStart &&
|
|
90
|
+
selectionEmpty &&
|
|
91
|
+
depth === 1
|
|
92
|
+
) {
|
|
93
|
+
return chain()
|
|
94
|
+
.command(mergeBlocksCommand(posBetweenBlocks))
|
|
95
|
+
.scrollIntoView()
|
|
96
|
+
.run();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return false;
|
|
100
|
+
}),
|
|
101
|
+
// Deletes previous block if it contains no content and isn't a table,
|
|
102
|
+
// when the selection is empty and at the start of the block. Moves the
|
|
103
|
+
// current block into the deleted block's place.
|
|
104
|
+
() =>
|
|
105
|
+
commands.command(({ state }) => {
|
|
106
|
+
const blockInfo = getBlockInfoFromSelection(state);
|
|
107
|
+
|
|
108
|
+
const { depth } = state.doc.resolve(
|
|
109
|
+
blockInfo.blockContainer.beforePos
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const selectionAtBlockStart =
|
|
113
|
+
state.selection.from === blockInfo.blockContent.beforePos + 1;
|
|
114
|
+
const selectionEmpty = state.selection.empty;
|
|
115
|
+
const blockAtDocStart = blockInfo.blockContainer.beforePos === 1;
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
!blockAtDocStart &&
|
|
119
|
+
selectionAtBlockStart &&
|
|
120
|
+
selectionEmpty &&
|
|
121
|
+
depth === 1
|
|
122
|
+
) {
|
|
123
|
+
const prevBlockPos = getPrevBlockPos(
|
|
124
|
+
state.doc,
|
|
125
|
+
state.doc.resolve(blockInfo.blockContainer.beforePos)
|
|
126
|
+
);
|
|
127
|
+
const prevBlockInfo = getBlockInfoFromResolvedPos(
|
|
128
|
+
state.doc.resolve(prevBlockPos.pos)
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const prevBlockNotTableAndNoContent =
|
|
132
|
+
prevBlockInfo.blockContent.node.type.spec.content === "" ||
|
|
133
|
+
(prevBlockInfo.blockContent.node.type.spec.content ===
|
|
134
|
+
"inline*" &&
|
|
135
|
+
prevBlockInfo.blockContent.node.childCount === 0);
|
|
136
|
+
|
|
137
|
+
if (prevBlockNotTableAndNoContent) {
|
|
138
|
+
return chain()
|
|
139
|
+
.cut(
|
|
140
|
+
{
|
|
141
|
+
from: blockInfo.blockContainer.beforePos,
|
|
142
|
+
to: blockInfo.blockContainer.afterPos,
|
|
143
|
+
},
|
|
144
|
+
prevBlockInfo.blockContainer.afterPos
|
|
145
|
+
)
|
|
146
|
+
.deleteRange({
|
|
147
|
+
from: prevBlockInfo.blockContainer.beforePos,
|
|
148
|
+
to: prevBlockInfo.blockContainer.afterPos,
|
|
149
|
+
})
|
|
150
|
+
.run();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return false;
|
|
155
|
+
}),
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
const handleDelete = () =>
|
|
159
|
+
this.editor.commands.first(({ commands }) => [
|
|
160
|
+
// Deletes the selection if it's not empty.
|
|
161
|
+
() => commands.deleteSelection(),
|
|
162
|
+
// Merges block with the next one (at the same nesting level or lower),
|
|
163
|
+
// if one exists, the block has no children, and the selection is at the
|
|
164
|
+
// end of the block.
|
|
165
|
+
() =>
|
|
166
|
+
commands.command(({ state }) => {
|
|
167
|
+
// TODO: Change this to not rely on offsets & schema assumptions
|
|
168
|
+
const { blockContainer, blockContent, blockGroup } =
|
|
169
|
+
getBlockInfoFromSelection(state);
|
|
170
|
+
|
|
171
|
+
const { depth } = state.doc.resolve(blockContainer.beforePos);
|
|
172
|
+
const blockAtDocEnd =
|
|
173
|
+
blockContainer.afterPos === state.doc.nodeSize - 3;
|
|
174
|
+
const selectionAtBlockEnd =
|
|
175
|
+
state.selection.from === blockContent.afterPos - 1;
|
|
176
|
+
const selectionEmpty = state.selection.empty;
|
|
177
|
+
const hasChildBlocks = blockGroup !== undefined;
|
|
178
|
+
|
|
179
|
+
if (
|
|
180
|
+
!blockAtDocEnd &&
|
|
181
|
+
selectionAtBlockEnd &&
|
|
182
|
+
selectionEmpty &&
|
|
183
|
+
!hasChildBlocks
|
|
184
|
+
) {
|
|
185
|
+
let oldDepth = depth;
|
|
186
|
+
let newPos = blockContainer.afterPos + 1;
|
|
187
|
+
let newDepth = state.doc.resolve(newPos).depth;
|
|
188
|
+
|
|
189
|
+
while (newDepth < oldDepth) {
|
|
190
|
+
oldDepth = newDepth;
|
|
191
|
+
newPos += 2;
|
|
192
|
+
newDepth = state.doc.resolve(newPos).depth;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return commands.command(mergeBlocksCommand(newPos - 1));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return false;
|
|
199
|
+
}),
|
|
200
|
+
]);
|
|
201
|
+
|
|
202
|
+
const handleEnter = () =>
|
|
203
|
+
this.editor.commands.first(({ commands }) => [
|
|
204
|
+
// Removes a level of nesting if the block is empty & indented, while the selection is also empty & at the start
|
|
205
|
+
// of the block.
|
|
206
|
+
() =>
|
|
207
|
+
commands.command(({ state }) => {
|
|
208
|
+
const { blockContent, blockContainer } =
|
|
209
|
+
getBlockInfoFromSelection(state);
|
|
210
|
+
|
|
211
|
+
const { depth } = state.doc.resolve(blockContainer.beforePos);
|
|
212
|
+
|
|
213
|
+
const selectionAtBlockStart =
|
|
214
|
+
state.selection.$anchor.parentOffset === 0;
|
|
215
|
+
const selectionEmpty =
|
|
216
|
+
state.selection.anchor === state.selection.head;
|
|
217
|
+
const blockEmpty = blockContent.node.childCount === 0;
|
|
218
|
+
const blockIndented = depth > 1;
|
|
219
|
+
|
|
220
|
+
if (
|
|
221
|
+
selectionAtBlockStart &&
|
|
222
|
+
selectionEmpty &&
|
|
223
|
+
blockEmpty &&
|
|
224
|
+
blockIndented
|
|
225
|
+
) {
|
|
226
|
+
return commands.liftListItem("blockContainer");
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return false;
|
|
230
|
+
}),
|
|
231
|
+
// Creates a new block and moves the selection to it if the current one is empty, while the selection is also
|
|
232
|
+
// empty & at the start of the block.
|
|
233
|
+
() =>
|
|
234
|
+
commands.command(({ state, dispatch }) => {
|
|
235
|
+
const { blockContainer, blockContent } =
|
|
236
|
+
getBlockInfoFromSelection(state);
|
|
237
|
+
|
|
238
|
+
const selectionAtBlockStart =
|
|
239
|
+
state.selection.$anchor.parentOffset === 0;
|
|
240
|
+
const selectionEmpty =
|
|
241
|
+
state.selection.anchor === state.selection.head;
|
|
242
|
+
const blockEmpty = blockContent.node.childCount === 0;
|
|
243
|
+
|
|
244
|
+
if (selectionAtBlockStart && selectionEmpty && blockEmpty) {
|
|
245
|
+
const newBlockInsertionPos = blockContainer.afterPos;
|
|
246
|
+
const newBlockContentPos = newBlockInsertionPos + 2;
|
|
247
|
+
|
|
248
|
+
if (dispatch) {
|
|
249
|
+
const newBlock =
|
|
250
|
+
state.schema.nodes["blockContainer"].createAndFill()!;
|
|
251
|
+
|
|
252
|
+
state.tr
|
|
253
|
+
.insert(newBlockInsertionPos, newBlock)
|
|
254
|
+
.scrollIntoView();
|
|
255
|
+
state.tr.setSelection(
|
|
256
|
+
new TextSelection(state.doc.resolve(newBlockContentPos))
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return false;
|
|
264
|
+
}),
|
|
265
|
+
// Splits the current block, moving content inside that's after the cursor to a new text block below. Also
|
|
266
|
+
// deletes the selection beforehand, if it's not empty.
|
|
267
|
+
() =>
|
|
268
|
+
commands.command(({ state, chain }) => {
|
|
269
|
+
const { blockContent } = getBlockInfoFromSelection(state);
|
|
270
|
+
|
|
271
|
+
const selectionAtBlockStart =
|
|
272
|
+
state.selection.$anchor.parentOffset === 0;
|
|
273
|
+
const blockEmpty = blockContent.node.childCount === 0;
|
|
274
|
+
|
|
275
|
+
if (!blockEmpty) {
|
|
276
|
+
chain()
|
|
277
|
+
.deleteSelection()
|
|
278
|
+
.command(
|
|
279
|
+
splitBlockCommand(
|
|
280
|
+
state.selection.from,
|
|
281
|
+
selectionAtBlockStart,
|
|
282
|
+
selectionAtBlockStart
|
|
283
|
+
)
|
|
284
|
+
)
|
|
285
|
+
.run();
|
|
286
|
+
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return false;
|
|
291
|
+
}),
|
|
292
|
+
]);
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
Backspace: handleBackspace,
|
|
296
|
+
Delete: handleDelete,
|
|
297
|
+
Enter: handleEnter,
|
|
298
|
+
// Always returning true for tab key presses ensures they're not captured by the browser. Otherwise, they blur the
|
|
299
|
+
// editor since the browser will try to use tab for keyboard navigation.
|
|
300
|
+
Tab: () => {
|
|
301
|
+
if (
|
|
302
|
+
this.options.editor.formattingToolbar?.shown ||
|
|
303
|
+
this.options.editor.linkToolbar?.shown ||
|
|
304
|
+
this.options.editor.filePanel?.shown
|
|
305
|
+
) {
|
|
306
|
+
// don't handle tabs if a toolbar is shown, so we can tab into / out of it
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
this.editor.commands.sinkListItem("blockContainer");
|
|
310
|
+
return true;
|
|
311
|
+
},
|
|
312
|
+
"Shift-Tab": () => {
|
|
313
|
+
if (
|
|
314
|
+
this.options.editor.formattingToolbar?.shown ||
|
|
315
|
+
this.options.editor.linkToolbar?.shown ||
|
|
316
|
+
this.options.editor.filePanel?.shown
|
|
317
|
+
) {
|
|
318
|
+
// don't handle tabs if a toolbar is shown, so we can tab into / out of it
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
this.editor.commands.liftListItem("blockContainer");
|
|
322
|
+
return true;
|
|
323
|
+
},
|
|
324
|
+
"Shift-Mod-ArrowUp": () => {
|
|
325
|
+
this.options.editor.moveBlockUp();
|
|
326
|
+
return true;
|
|
327
|
+
},
|
|
328
|
+
"Shift-Mod-ArrowDown": () => {
|
|
329
|
+
this.options.editor.moveBlockDown();
|
|
330
|
+
return true;
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
},
|
|
334
|
+
});
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { getMarkRange, posToDOMRect, Range } from "@tiptap/core";
|
|
2
|
+
|
|
2
3
|
import { EditorView } from "@tiptap/pm/view";
|
|
3
4
|
import { Mark } from "prosemirror-model";
|
|
4
5
|
import { Plugin, PluginKey, PluginView } from "prosemirror-state";
|
|
5
6
|
|
|
6
|
-
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
|
|
7
|
-
import { UiElementPosition } from "../../extensions-shared/UiElementPosition";
|
|
8
|
-
import {
|
|
9
|
-
|
|
7
|
+
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
|
|
8
|
+
import { UiElementPosition } from "../../extensions-shared/UiElementPosition.js";
|
|
9
|
+
import {
|
|
10
|
+
BlockSchema,
|
|
11
|
+
InlineContentSchema,
|
|
12
|
+
StyleSchema,
|
|
13
|
+
} from "../../schema/index.js";
|
|
14
|
+
import { EventEmitter } from "../../util/EventEmitter.js";
|
|
10
15
|
|
|
11
16
|
export type LinkToolbarState = UiElementPosition & {
|
|
12
17
|
// The hovered link's URL, and the text it's displayed with in the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Plugin, PluginKey, TextSelection } from "prosemirror-state";
|
|
2
2
|
|
|
3
|
-
const PLUGIN_KEY = new PluginKey("
|
|
3
|
+
const PLUGIN_KEY = new PluginKey("node-selection-keyboard");
|
|
4
4
|
// By default, typing with a node selection active will cause ProseMirror to
|
|
5
5
|
// replace the node with one that contains editable content. This plugin blocks
|
|
6
6
|
// this behaviour without also blocking things like keyboard shortcuts:
|
|
@@ -15,7 +15,7 @@ const PLUGIN_KEY = new PluginKey("non-editable-block");
|
|
|
15
15
|
// While a more elegant solution would probably process transactions instead of
|
|
16
16
|
// keystrokes, this brings us most of the way to Notion's UX without much added
|
|
17
17
|
// complexity.
|
|
18
|
-
export const
|
|
18
|
+
export const NodeSelectionKeyboardPlugin = () => {
|
|
19
19
|
return new Plugin({
|
|
20
20
|
key: PLUGIN_KEY,
|
|
21
21
|
props: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Plugin, PluginKey } from "prosemirror-state";
|
|
2
2
|
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
3
|
-
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
|
|
3
|
+
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
|
|
4
4
|
|
|
5
5
|
const PLUGIN_KEY = new PluginKey(`blocknote-placeholder`);
|
|
6
6
|
|