@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
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { setupTestEnv } from "../../setupTestEnv.js";
|
|
4
|
+
import { updateBlock } from "./updateBlock.js";
|
|
5
|
+
|
|
6
|
+
const getEditor = setupTestEnv();
|
|
7
|
+
|
|
8
|
+
describe("Test updateBlock typing", () => {
|
|
9
|
+
it("Type is inferred correctly", () => {
|
|
10
|
+
try {
|
|
11
|
+
getEditor().updateBlock(
|
|
12
|
+
{ id: "placeholder-id" },
|
|
13
|
+
{
|
|
14
|
+
// @ts-expect-error invalid type
|
|
15
|
+
type: "non-existing",
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
} catch (e) {
|
|
19
|
+
// ID doesn't exist, which is fine - this is a compile-time check
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("Props are inferred correctly", () => {
|
|
24
|
+
try {
|
|
25
|
+
getEditor().updateBlock(
|
|
26
|
+
{ id: "placeholder-id" },
|
|
27
|
+
{
|
|
28
|
+
type: "paragraph",
|
|
29
|
+
props: {
|
|
30
|
+
// @ts-expect-error invalid type
|
|
31
|
+
level: 1,
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
// ID doesn't exist, which is fine - this is a compile-time check
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
getEditor().updateBlock(
|
|
40
|
+
{ id: "placeholder-id" },
|
|
41
|
+
{
|
|
42
|
+
type: "heading",
|
|
43
|
+
props: {
|
|
44
|
+
level: 1,
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
// ID doesn't exist, which is fine - this is a compile-time check
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("Test updateBlock", () => {
|
|
55
|
+
it.skip("Update ID", () => {
|
|
56
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
57
|
+
id: "new-id",
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("Update type", () => {
|
|
64
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
65
|
+
type: "paragraph",
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("Update single prop", () => {
|
|
72
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
73
|
+
props: {
|
|
74
|
+
level: 3,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("Update all props", () => {
|
|
82
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
83
|
+
props: {
|
|
84
|
+
backgroundColor: "blue",
|
|
85
|
+
level: 3,
|
|
86
|
+
textAlignment: "right",
|
|
87
|
+
textColor: "blue",
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("Revert single prop", () => {
|
|
95
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
96
|
+
props: {
|
|
97
|
+
level: undefined,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("Revert all props", () => {
|
|
105
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
106
|
+
props: {
|
|
107
|
+
backgroundColor: undefined,
|
|
108
|
+
level: undefined,
|
|
109
|
+
textAlignment: undefined,
|
|
110
|
+
textColor: undefined,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("Update with plain content", () => {
|
|
118
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
119
|
+
content: "New content",
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("Update with styled content", () => {
|
|
126
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
127
|
+
content: [
|
|
128
|
+
{ type: "text", text: "New", styles: { backgroundColor: "blue" } },
|
|
129
|
+
{ type: "text", text: " ", styles: {} },
|
|
130
|
+
{ type: "text", text: "content", styles: { backgroundColor: "blue" } },
|
|
131
|
+
],
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("Update children", () => {
|
|
138
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
139
|
+
children: [
|
|
140
|
+
{
|
|
141
|
+
id: "new-nested-paragraph",
|
|
142
|
+
type: "paragraph",
|
|
143
|
+
content: "New nested Paragraph 2",
|
|
144
|
+
children: [
|
|
145
|
+
{
|
|
146
|
+
id: "new-double-nested-paragraph",
|
|
147
|
+
type: "paragraph",
|
|
148
|
+
content: "New double Nested Paragraph 2",
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it.skip("Update everything", () => {
|
|
159
|
+
updateBlock(getEditor(), "heading-with-everything", {
|
|
160
|
+
id: "new-id",
|
|
161
|
+
type: "paragraph",
|
|
162
|
+
props: {
|
|
163
|
+
backgroundColor: "blue",
|
|
164
|
+
textAlignment: "right",
|
|
165
|
+
textColor: "blue",
|
|
166
|
+
},
|
|
167
|
+
content: [
|
|
168
|
+
{ type: "text", text: "New", styles: { backgroundColor: "blue" } },
|
|
169
|
+
{ type: "text", text: " ", styles: {} },
|
|
170
|
+
{ type: "text", text: "content", styles: { backgroundColor: "blue" } },
|
|
171
|
+
],
|
|
172
|
+
children: [
|
|
173
|
+
{
|
|
174
|
+
id: "new-nested-paragraph",
|
|
175
|
+
type: "paragraph",
|
|
176
|
+
content: "New nested Paragraph 2",
|
|
177
|
+
children: [
|
|
178
|
+
{
|
|
179
|
+
id: "new-double-nested-paragraph",
|
|
180
|
+
type: "paragraph",
|
|
181
|
+
content: "New double Nested Paragraph 2",
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("Update inline content to empty table content", () => {
|
|
192
|
+
updateBlock(getEditor(), "paragraph-0", {
|
|
193
|
+
type: "table",
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("Update table content to empty inline content", () => {
|
|
200
|
+
updateBlock(getEditor(), "table-0", {
|
|
201
|
+
type: "paragraph",
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("Update inline content to table content", () => {
|
|
208
|
+
updateBlock(getEditor(), "paragraph-0", {
|
|
209
|
+
type: "table",
|
|
210
|
+
content: {
|
|
211
|
+
type: "tableContent",
|
|
212
|
+
rows: [
|
|
213
|
+
{
|
|
214
|
+
cells: ["Cell 1", "Cell 2", "Cell 3"],
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
cells: ["Cell 4", "Cell 5", "Cell 6"],
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
cells: ["Cell 7", "Cell 8", "Cell 9"],
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("Update table content to inline content", () => {
|
|
230
|
+
updateBlock(getEditor(), "table-0", {
|
|
231
|
+
type: "paragraph",
|
|
232
|
+
content: "Paragraph",
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("Update inline content to no content", () => {
|
|
239
|
+
updateBlock(getEditor(), "paragraph-0", {
|
|
240
|
+
type: "image",
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("Update no content to empty inline content", () => {
|
|
247
|
+
updateBlock(getEditor(), "image-0", {
|
|
248
|
+
type: "paragraph",
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("Update no content to inline content", () => {
|
|
255
|
+
updateBlock(getEditor(), "image-0", {
|
|
256
|
+
type: "paragraph",
|
|
257
|
+
content: "Paragraph",
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("Update no content to empty table content", () => {
|
|
264
|
+
updateBlock(getEditor(), "image-0", {
|
|
265
|
+
type: "table",
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("Update no content to table content", () => {
|
|
272
|
+
updateBlock(getEditor(), "image-0", {
|
|
273
|
+
type: "table",
|
|
274
|
+
content: {
|
|
275
|
+
type: "tableContent",
|
|
276
|
+
rows: [
|
|
277
|
+
{
|
|
278
|
+
cells: ["Cell 1", "Cell 2", "Cell 3"],
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
cells: ["Cell 4", "Cell 5", "Cell 6"],
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
cells: ["Cell 7", "Cell 8", "Cell 9"],
|
|
285
|
+
},
|
|
286
|
+
],
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it("Update table content to no content", () => {
|
|
294
|
+
updateBlock(getEditor(), "table-0", {
|
|
295
|
+
type: "image",
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Fragment, Node as PMNode, Slice } from "prosemirror-model";
|
|
2
|
+
import { EditorState } from "prosemirror-state";
|
|
3
|
+
|
|
4
|
+
import { Block, PartialBlock } from "../../../../blocks/defaultBlocks.js";
|
|
5
|
+
import { BlockNoteEditor } from "../../../../editor/BlockNoteEditor.js";
|
|
6
|
+
import {
|
|
7
|
+
BlockIdentifier,
|
|
8
|
+
BlockSchema,
|
|
9
|
+
} from "../../../../schema/blocks/types.js";
|
|
10
|
+
import { InlineContentSchema } from "../../../../schema/inlineContent/types.js";
|
|
11
|
+
import { StyleSchema } from "../../../../schema/styles/types.js";
|
|
12
|
+
import { UnreachableCaseError } from "../../../../util/typescript.js";
|
|
13
|
+
import { getBlockInfoFromResolvedPos } from "../../../getBlockInfoFromPos.js";
|
|
14
|
+
import {
|
|
15
|
+
blockToNode,
|
|
16
|
+
inlineContentToNodes,
|
|
17
|
+
tableContentToNodes,
|
|
18
|
+
} from "../../../nodeConversions/blockToNode.js";
|
|
19
|
+
import { nodeToBlock } from "../../../nodeConversions/nodeToBlock.js";
|
|
20
|
+
import { getNodeById } from "../../../nodeUtil.js";
|
|
21
|
+
|
|
22
|
+
export const updateBlockCommand =
|
|
23
|
+
<
|
|
24
|
+
BSchema extends BlockSchema,
|
|
25
|
+
I extends InlineContentSchema,
|
|
26
|
+
S extends StyleSchema
|
|
27
|
+
>(
|
|
28
|
+
editor: BlockNoteEditor<BSchema, I, S>,
|
|
29
|
+
posBeforeBlock: number,
|
|
30
|
+
block: PartialBlock<BSchema, I, S>
|
|
31
|
+
) =>
|
|
32
|
+
({
|
|
33
|
+
state,
|
|
34
|
+
dispatch,
|
|
35
|
+
}: {
|
|
36
|
+
state: EditorState;
|
|
37
|
+
dispatch: ((args?: any) => any) | undefined;
|
|
38
|
+
}) => {
|
|
39
|
+
const { blockContainer, blockContent, blockGroup } =
|
|
40
|
+
getBlockInfoFromResolvedPos(state.doc.resolve(posBeforeBlock));
|
|
41
|
+
|
|
42
|
+
if (dispatch) {
|
|
43
|
+
// Adds blockGroup node with child blocks if necessary.
|
|
44
|
+
if (block.children !== undefined) {
|
|
45
|
+
const childNodes = [];
|
|
46
|
+
|
|
47
|
+
// Creates ProseMirror nodes for each child block, including their descendants.
|
|
48
|
+
for (const child of block.children) {
|
|
49
|
+
childNodes.push(
|
|
50
|
+
blockToNode(child, state.schema, editor.schema.styleSchema)
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Checks if a blockGroup node already exists.
|
|
55
|
+
if (blockGroup) {
|
|
56
|
+
// Replaces all child nodes in the existing blockGroup with the ones created earlier.
|
|
57
|
+
state.tr.replace(
|
|
58
|
+
blockGroup.beforePos + 1,
|
|
59
|
+
blockGroup.afterPos - 1,
|
|
60
|
+
new Slice(Fragment.from(childNodes), 0, 0)
|
|
61
|
+
);
|
|
62
|
+
} else {
|
|
63
|
+
// Inserts a new blockGroup containing the child nodes created earlier.
|
|
64
|
+
state.tr.insert(
|
|
65
|
+
blockContent.afterPos,
|
|
66
|
+
state.schema.nodes["blockGroup"].create({}, childNodes)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const oldType = blockContent.node.type.name;
|
|
72
|
+
const newType = block.type || oldType;
|
|
73
|
+
|
|
74
|
+
// The code below determines the new content of the block.
|
|
75
|
+
// or "keep" to keep as-is
|
|
76
|
+
let content: PMNode[] | "keep" = "keep";
|
|
77
|
+
|
|
78
|
+
// Has there been any custom content provided?
|
|
79
|
+
if (block.content) {
|
|
80
|
+
if (typeof block.content === "string") {
|
|
81
|
+
// Adds a single text node with no marks to the content.
|
|
82
|
+
content = inlineContentToNodes(
|
|
83
|
+
[block.content],
|
|
84
|
+
state.schema,
|
|
85
|
+
editor.schema.styleSchema
|
|
86
|
+
);
|
|
87
|
+
} else if (Array.isArray(block.content)) {
|
|
88
|
+
// Adds a text node with the provided styles converted into marks to the content,
|
|
89
|
+
// for each InlineContent object.
|
|
90
|
+
content = inlineContentToNodes(
|
|
91
|
+
block.content,
|
|
92
|
+
state.schema,
|
|
93
|
+
editor.schema.styleSchema
|
|
94
|
+
);
|
|
95
|
+
} else if (block.content.type === "tableContent") {
|
|
96
|
+
content = tableContentToNodes(
|
|
97
|
+
block.content,
|
|
98
|
+
state.schema,
|
|
99
|
+
editor.schema.styleSchema
|
|
100
|
+
);
|
|
101
|
+
} else {
|
|
102
|
+
throw new UnreachableCaseError(block.content.type);
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
// no custom content has been provided, use existing content IF possible
|
|
106
|
+
|
|
107
|
+
// Since some block types contain inline content and others don't,
|
|
108
|
+
// we either need to call setNodeMarkup to just update type &
|
|
109
|
+
// attributes, or replaceWith to replace the whole blockContent.
|
|
110
|
+
const oldContentType = state.schema.nodes[oldType].spec.content;
|
|
111
|
+
const newContentType = state.schema.nodes[newType].spec.content;
|
|
112
|
+
|
|
113
|
+
if (oldContentType === "") {
|
|
114
|
+
// keep old content, because it's empty anyway and should be compatible with
|
|
115
|
+
// any newContentType
|
|
116
|
+
} else if (newContentType !== oldContentType) {
|
|
117
|
+
// the content type changed, replace the previous content
|
|
118
|
+
content = [];
|
|
119
|
+
} else {
|
|
120
|
+
// keep old content, because the content type is the same and should be compatible
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Now, changes the blockContent node type and adds the provided props
|
|
125
|
+
// as attributes. Also preserves all existing attributes that are
|
|
126
|
+
// compatible with the new type.
|
|
127
|
+
//
|
|
128
|
+
// Use either setNodeMarkup or replaceWith depending on whether the
|
|
129
|
+
// content is being replaced or not.
|
|
130
|
+
if (content === "keep") {
|
|
131
|
+
// use setNodeMarkup to only update the type and attributes
|
|
132
|
+
state.tr.setNodeMarkup(
|
|
133
|
+
blockContent.beforePos,
|
|
134
|
+
block.type === undefined ? undefined : state.schema.nodes[block.type],
|
|
135
|
+
{
|
|
136
|
+
...blockContent.node.attrs,
|
|
137
|
+
...block.props,
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
} else {
|
|
141
|
+
// use replaceWith to replace the content and the block itself
|
|
142
|
+
// also reset the selection since replacing the block content
|
|
143
|
+
// sets it to the next block.
|
|
144
|
+
state.tr.replaceWith(
|
|
145
|
+
blockContent.beforePos,
|
|
146
|
+
blockContent.afterPos,
|
|
147
|
+
state.schema.nodes[newType].create(
|
|
148
|
+
{
|
|
149
|
+
...blockContent.node.attrs,
|
|
150
|
+
...block.props,
|
|
151
|
+
},
|
|
152
|
+
content
|
|
153
|
+
)
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Adds all provided props as attributes to the parent blockContainer node too, and also preserves existing
|
|
158
|
+
// attributes.
|
|
159
|
+
state.tr.setNodeMarkup(blockContainer.beforePos, undefined, {
|
|
160
|
+
...blockContainer.node.attrs,
|
|
161
|
+
...block.props,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return true;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export function updateBlock<
|
|
169
|
+
BSchema extends BlockSchema,
|
|
170
|
+
I extends InlineContentSchema,
|
|
171
|
+
S extends StyleSchema
|
|
172
|
+
>(
|
|
173
|
+
editor: BlockNoteEditor<BSchema, I, S>,
|
|
174
|
+
blockToUpdate: BlockIdentifier,
|
|
175
|
+
update: PartialBlock<BSchema, I, S>
|
|
176
|
+
): Block<BSchema, I, S> {
|
|
177
|
+
const ttEditor = editor._tiptapEditor;
|
|
178
|
+
|
|
179
|
+
const id =
|
|
180
|
+
typeof blockToUpdate === "string" ? blockToUpdate : blockToUpdate.id;
|
|
181
|
+
const { posBeforeNode } = getNodeById(id, ttEditor.state.doc);
|
|
182
|
+
|
|
183
|
+
ttEditor.commands.command(({ state, dispatch }) => {
|
|
184
|
+
updateBlockCommand(editor, posBeforeNode, update)({ state, dispatch });
|
|
185
|
+
return true;
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const blockContainerNode = ttEditor.state.doc
|
|
189
|
+
.resolve(posBeforeNode + 1) // TODO: clean?
|
|
190
|
+
.node();
|
|
191
|
+
|
|
192
|
+
return nodeToBlock(
|
|
193
|
+
blockContainerNode,
|
|
194
|
+
editor.schema.blockSchema,
|
|
195
|
+
editor.schema.inlineContentSchema,
|
|
196
|
+
editor.schema.styleSchema,
|
|
197
|
+
editor.blockCache
|
|
198
|
+
);
|
|
199
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { selectionToInsertionEnd } from "@tiptap/core";
|
|
2
|
+
import { Node } from "prosemirror-model";
|
|
3
|
+
|
|
4
|
+
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
|
|
5
|
+
import {
|
|
6
|
+
BlockSchema,
|
|
7
|
+
InlineContentSchema,
|
|
8
|
+
StyleSchema,
|
|
9
|
+
} from "../../schema/index.js";
|
|
10
|
+
|
|
11
|
+
// similar to tiptap insertContentAt
|
|
12
|
+
export function insertContentAt<
|
|
13
|
+
BSchema extends BlockSchema,
|
|
14
|
+
I extends InlineContentSchema,
|
|
15
|
+
S extends StyleSchema
|
|
16
|
+
>(
|
|
17
|
+
position: any,
|
|
18
|
+
nodes: Node[],
|
|
19
|
+
editor: BlockNoteEditor<BSchema, I, S>,
|
|
20
|
+
options: {
|
|
21
|
+
updateSelection: boolean;
|
|
22
|
+
} = { updateSelection: true }
|
|
23
|
+
) {
|
|
24
|
+
const tr = editor._tiptapEditor.state.tr;
|
|
25
|
+
|
|
26
|
+
// don’t dispatch an empty fragment because this can lead to strange errors
|
|
27
|
+
// if (content.toString() === "<>") {
|
|
28
|
+
// return true;
|
|
29
|
+
// }
|
|
30
|
+
|
|
31
|
+
let { from, to } =
|
|
32
|
+
typeof position === "number"
|
|
33
|
+
? { from: position, to: position }
|
|
34
|
+
: { from: position.from, to: position.to };
|
|
35
|
+
|
|
36
|
+
let isOnlyTextContent = true;
|
|
37
|
+
let isOnlyBlockContent = true;
|
|
38
|
+
// const nodes = isFragment(content) ? content : [content];
|
|
39
|
+
|
|
40
|
+
let text = "";
|
|
41
|
+
|
|
42
|
+
nodes.forEach((node) => {
|
|
43
|
+
// check if added node is valid
|
|
44
|
+
node.check();
|
|
45
|
+
|
|
46
|
+
if (isOnlyTextContent && node.isText && node.marks.length === 0) {
|
|
47
|
+
text += node.text;
|
|
48
|
+
} else {
|
|
49
|
+
isOnlyTextContent = false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// check if we can replace the wrapping node by
|
|
56
|
+
// the newly inserted content
|
|
57
|
+
// example:
|
|
58
|
+
// replace an empty paragraph by an inserted image
|
|
59
|
+
// instead of inserting the image below the paragraph
|
|
60
|
+
if (from === to && isOnlyBlockContent) {
|
|
61
|
+
const { parent } = tr.doc.resolve(from);
|
|
62
|
+
const isEmptyTextBlock =
|
|
63
|
+
parent.isTextblock && !parent.type.spec.code && !parent.childCount;
|
|
64
|
+
|
|
65
|
+
if (isEmptyTextBlock) {
|
|
66
|
+
from -= 1;
|
|
67
|
+
to += 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// if there is only plain text we have to use `insertText`
|
|
72
|
+
// because this will keep the current marks
|
|
73
|
+
if (isOnlyTextContent) {
|
|
74
|
+
// if value is string, we can use it directly
|
|
75
|
+
// otherwise if it is an array, we have to join it
|
|
76
|
+
// if (Array.isArray(value)) {
|
|
77
|
+
// tr.insertText(value.map((v) => v.text || "").join(""), from, to);
|
|
78
|
+
// } else if (typeof value === "object" && !!value && !!value.text) {
|
|
79
|
+
// tr.insertText(value.text, from, to);
|
|
80
|
+
// } else {
|
|
81
|
+
// tr.insertText(value as string, from, to);
|
|
82
|
+
// }
|
|
83
|
+
tr.insertText(text, from, to);
|
|
84
|
+
} else {
|
|
85
|
+
tr.replaceWith(from, to, nodes);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// set cursor at end of inserted content
|
|
89
|
+
if (options.updateSelection) {
|
|
90
|
+
selectionToInsertionEnd(tr, tr.steps.length - 1, -1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
editor.dispatch(tr);
|
|
94
|
+
|
|
95
|
+
return true;
|
|
96
|
+
}
|