@blocknote/core 0.11.2 → 0.12.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/README.md +13 -17
- package/dist/blocknote.js +1662 -1447
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +6 -6
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +7 -3
- package/src/api/blockManipulation/blockManipulation.test.ts +19 -15
- package/src/api/blockManipulation/blockManipulation.ts +107 -17
- package/src/api/exporters/html/externalHTMLExporter.ts +3 -7
- package/src/api/exporters/html/htmlConversion.test.ts +6 -3
- package/src/api/exporters/html/internalHTMLSerializer.ts +3 -7
- package/src/api/exporters/html/util/sharedHTMLConversion.ts +3 -3
- package/src/api/exporters/markdown/markdownExporter.test.ts +7 -3
- package/src/api/exporters/markdown/markdownExporter.ts +2 -6
- package/src/api/getCurrentBlockContentType.ts +14 -0
- package/src/api/nodeConversions/nodeConversions.test.ts +14 -7
- package/src/api/nodeConversions/nodeConversions.ts +1 -2
- package/src/api/parsers/html/parseHTML.test.ts +5 -1
- package/src/api/parsers/html/parseHTML.ts +2 -6
- package/src/api/parsers/html/util/nestedLists.ts +11 -1
- package/src/api/parsers/markdown/parseMarkdown.test.ts +3 -0
- package/src/api/parsers/markdown/parseMarkdown.ts +2 -6
- package/src/api/testUtil/cases/customBlocks.ts +18 -16
- package/src/api/testUtil/cases/customInlineContent.ts +12 -13
- package/src/api/testUtil/cases/customStyles.ts +12 -10
- package/src/api/testUtil/index.ts +4 -2
- package/src/api/testUtil/partialBlockTestUtil.ts +2 -6
- package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +50 -21
- package/src/blocks/ImageBlockContent/ImageBlockContent.ts +1 -2
- package/src/blocks/ImageBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.ts +8 -1
- package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +18 -5
- package/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts +7 -1
- package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +18 -5
- package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +14 -5
- package/src/blocks/defaultBlockHelpers.ts +3 -3
- package/src/blocks/defaultBlockTypeGuards.ts +84 -0
- package/src/blocks/defaultBlocks.ts +29 -3
- package/src/editor/Block.css +2 -31
- package/src/editor/BlockNoteEditor.ts +223 -267
- package/src/editor/BlockNoteExtensions.ts +5 -2
- package/src/editor/BlockNoteSchema.ts +98 -0
- package/src/editor/BlockNoteTipTapEditor.ts +162 -0
- package/src/editor/cursorPositionTypes.ts +2 -6
- package/src/editor/editor.css +0 -1
- package/src/editor/selectionTypes.ts +2 -6
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +22 -29
- package/src/extensions/{ImageToolbar → ImagePanel}/ImageToolbarPlugin.ts +54 -60
- package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +330 -0
- package/src/extensions/Placeholder/PlaceholderExtension.ts +81 -88
- package/src/extensions/SideMenu/SideMenuPlugin.ts +55 -56
- package/src/extensions/SuggestionMenu/DefaultSuggestionItem.ts +8 -0
- package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +353 -0
- package/src/extensions/{SlashMenu/defaultSlashMenuItems.ts → SuggestionMenu/getDefaultSlashMenuItems.ts} +119 -89
- package/src/extensions/TableHandles/TableHandlesPlugin.ts +62 -45
- package/src/extensions-shared/UiElementPosition.ts +4 -0
- package/src/index.ts +8 -8
- package/src/pm-nodes/BlockContainer.ts +5 -5
- package/src/schema/blocks/types.ts +15 -15
- package/src/schema/inlineContent/createSpec.ts +2 -2
- package/src/schema/inlineContent/types.ts +1 -1
- package/src/util/browser.ts +6 -4
- package/src/util/typescript.ts +7 -4
- package/types/src/api/blockManipulation/blockManipulation.d.ts +6 -1
- package/types/src/api/exporters/html/externalHTMLExporter.d.ts +2 -1
- package/types/src/api/exporters/html/internalHTMLSerializer.d.ts +2 -1
- package/types/src/api/exporters/markdown/markdownExporter.d.ts +2 -1
- package/types/src/api/getCurrentBlockContentType.d.ts +2 -0
- package/types/src/api/nodeConversions/nodeConversions.d.ts +2 -1
- package/types/src/api/parsers/html/parseHTML.d.ts +2 -1
- package/types/src/api/parsers/markdown/parseMarkdown.d.ts +2 -1
- package/types/src/api/testUtil/cases/customBlocks.d.ts +72 -13
- package/types/src/api/testUtil/cases/customInlineContent.d.ts +281 -6
- package/types/src/api/testUtil/cases/customStyles.d.ts +247 -13
- package/types/src/api/testUtil/index.d.ts +4 -2
- package/types/src/api/testUtil/partialBlockTestUtil.d.ts +2 -1
- package/types/src/blocks/ImageBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.d.ts +6 -1
- package/types/src/blocks/defaultBlockHelpers.d.ts +2 -2
- package/types/src/blocks/defaultBlockTypeGuards.d.ts +24 -0
- package/types/src/blocks/defaultBlocks.d.ts +21 -15
- package/types/src/editor/BlockNoteEditor.d.ts +51 -56
- package/types/src/editor/BlockNoteExtensions.d.ts +1 -0
- package/types/src/editor/BlockNoteSchema.d.ts +34 -0
- package/types/src/editor/BlockNoteTipTapEditor.d.ts +28 -0
- package/types/src/editor/cursorPositionTypes.d.ts +2 -1
- package/types/src/editor/selectionTypes.d.ts +2 -1
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +5 -6
- package/types/src/extensions/ImagePanel/ImageToolbarPlugin.d.ts +32 -0
- package/types/src/extensions/LinkToolbar/LinkToolbarPlugin.d.ts +40 -0
- package/types/src/extensions/Placeholder/PlaceholderExtension.d.ts +2 -15
- package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +8 -7
- package/types/src/extensions/SuggestionMenu/DefaultSuggestionItem.d.ts +8 -0
- package/types/src/extensions/SuggestionMenu/SuggestionPlugin.d.ts +31 -0
- package/types/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.d.ts +10 -0
- package/types/src/extensions/TableHandles/TableHandlesPlugin.d.ts +7 -7
- package/types/src/extensions-shared/UiElementPosition.d.ts +4 -0
- package/types/src/index.d.ts +8 -8
- package/types/src/pm-nodes/BlockContainer.d.ts +3 -2
- package/types/src/pm-nodes/BlockGroup.d.ts +1 -1
- package/types/src/schema/blocks/types.d.ts +15 -15
- package/types/src/schema/inlineContent/types.d.ts +1 -1
- package/types/src/util/browser.d.ts +1 -0
- package/types/src/util/typescript.d.ts +1 -0
- package/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts +0 -335
- package/src/extensions/SlashMenu/BaseSlashMenuItem.ts +0 -12
- package/src/extensions/SlashMenu/SlashMenuPlugin.ts +0 -53
- package/src/extensions-shared/BaseUiElementTypes.ts +0 -8
- package/src/extensions-shared/README.md +0 -3
- package/src/extensions-shared/suggestion/SuggestionItem.ts +0 -3
- package/src/extensions-shared/suggestion/SuggestionPlugin.ts +0 -448
- package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.d.ts +0 -38
- package/types/src/extensions/ImageToolbar/ImageToolbarPlugin.d.ts +0 -31
- package/types/src/extensions/SlashMenu/BaseSlashMenuItem.d.ts +0 -7
- package/types/src/extensions/SlashMenu/SlashMenuPlugin.d.ts +0 -13
- package/types/src/extensions/SlashMenu/defaultSlashMenuItems.d.ts +0 -3
- package/types/src/extensions-shared/BaseUiElementTypes.d.ts +0 -7
- package/types/src/extensions-shared/suggestion/SuggestionItem.d.ts +0 -3
- package/types/src/extensions-shared/suggestion/SuggestionPlugin.d.ts +0 -36
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-100.woff +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-100.woff2 +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-200.woff +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-200.woff2 +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-300.woff +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-300.woff2 +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-500.woff +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-500.woff2 +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-600.woff +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-600.woff2 +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-700.woff +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-700.woff2 +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-800.woff +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-800.woff2 +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-900.woff +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-900.woff2 +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-regular.woff +0 -0
- /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-regular.woff2 +0 -0
- /package/src/{assets/fonts-inter.css → fonts/inter.css} +0 -0
|
@@ -39,6 +39,7 @@ export const getBlockNoteExtensions = <
|
|
|
39
39
|
S extends StyleSchema
|
|
40
40
|
>(opts: {
|
|
41
41
|
editor: BlockNoteEditor<BSchema, I, S>;
|
|
42
|
+
placeholders?: Record<string | "default", string>;
|
|
42
43
|
domAttributes: Partial<BlockNoteDOMAttributes>;
|
|
43
44
|
blockSchema: BSchema;
|
|
44
45
|
blockSpecs: BlockSpecs;
|
|
@@ -66,8 +67,10 @@ export const getBlockNoteExtensions = <
|
|
|
66
67
|
|
|
67
68
|
// DropCursor,
|
|
68
69
|
Placeholder.configure({
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
// TODO: This shorthand is kind of ugly
|
|
71
|
+
...(opts.placeholders !== undefined
|
|
72
|
+
? { placeholders: opts.placeholders }
|
|
73
|
+
: {}),
|
|
71
74
|
}),
|
|
72
75
|
UniqueID.configure({
|
|
73
76
|
types: ["blockContainer"],
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultBlockSpecs,
|
|
3
|
+
defaultInlineContentSpecs,
|
|
4
|
+
defaultStyleSpecs,
|
|
5
|
+
} from "../blocks/defaultBlocks";
|
|
6
|
+
import {
|
|
7
|
+
BlockSchema,
|
|
8
|
+
BlockSchemaFromSpecs,
|
|
9
|
+
BlockSpecs,
|
|
10
|
+
InlineContentSchema,
|
|
11
|
+
InlineContentSchemaFromSpecs,
|
|
12
|
+
InlineContentSpecs,
|
|
13
|
+
StyleSchema,
|
|
14
|
+
StyleSchemaFromSpecs,
|
|
15
|
+
StyleSpecs,
|
|
16
|
+
getBlockSchemaFromSpecs,
|
|
17
|
+
getInlineContentSchemaFromSpecs,
|
|
18
|
+
getStyleSchemaFromSpecs,
|
|
19
|
+
} from "../schema";
|
|
20
|
+
import type {
|
|
21
|
+
BlockNoDefaults,
|
|
22
|
+
PartialBlockNoDefaults,
|
|
23
|
+
} from "../schema/blocks/types";
|
|
24
|
+
import type { BlockNoteEditor } from "./BlockNoteEditor";
|
|
25
|
+
|
|
26
|
+
export class BlockNoteSchema<
|
|
27
|
+
BSchema extends BlockSchema,
|
|
28
|
+
ISchema extends InlineContentSchema,
|
|
29
|
+
SSchema extends StyleSchema
|
|
30
|
+
> {
|
|
31
|
+
public readonly blockSpecs: BlockSpecs;
|
|
32
|
+
public readonly inlineContentSpecs: InlineContentSpecs;
|
|
33
|
+
public readonly styleSpecs: StyleSpecs;
|
|
34
|
+
|
|
35
|
+
public readonly blockSchema: BSchema;
|
|
36
|
+
public readonly inlineContentSchema: ISchema;
|
|
37
|
+
public readonly styleSchema: SSchema;
|
|
38
|
+
|
|
39
|
+
// Helper so that you can use typeof schema.BlockNoteEditor
|
|
40
|
+
public readonly BlockNoteEditor: BlockNoteEditor<BSchema, ISchema, SSchema> =
|
|
41
|
+
"only for types" as any;
|
|
42
|
+
|
|
43
|
+
public readonly Block: BlockNoDefaults<BSchema, ISchema, SSchema> =
|
|
44
|
+
"only for types" as any;
|
|
45
|
+
|
|
46
|
+
public readonly PartialBlock: PartialBlockNoDefaults<
|
|
47
|
+
BSchema,
|
|
48
|
+
ISchema,
|
|
49
|
+
SSchema
|
|
50
|
+
> = "only for types" as any;
|
|
51
|
+
|
|
52
|
+
public static create<
|
|
53
|
+
BSpecs extends BlockSpecs = typeof defaultBlockSpecs,
|
|
54
|
+
ISpecs extends InlineContentSpecs = typeof defaultInlineContentSpecs,
|
|
55
|
+
SSpecs extends StyleSpecs = typeof defaultStyleSpecs
|
|
56
|
+
>(options?: {
|
|
57
|
+
/**
|
|
58
|
+
* A list of custom block types that should be available in the editor.
|
|
59
|
+
*/
|
|
60
|
+
blockSpecs?: BSpecs;
|
|
61
|
+
/**
|
|
62
|
+
* A list of custom InlineContent types that should be available in the editor.
|
|
63
|
+
*/
|
|
64
|
+
inlineContentSpecs?: ISpecs;
|
|
65
|
+
/**
|
|
66
|
+
* A list of custom Styles that should be available in the editor.
|
|
67
|
+
*/
|
|
68
|
+
styleSpecs?: SSpecs;
|
|
69
|
+
}) {
|
|
70
|
+
return new BlockNoteSchema<
|
|
71
|
+
BlockSchemaFromSpecs<BSpecs>,
|
|
72
|
+
InlineContentSchemaFromSpecs<ISpecs>,
|
|
73
|
+
StyleSchemaFromSpecs<SSpecs>
|
|
74
|
+
>(options);
|
|
75
|
+
// as BlockNoteSchema<
|
|
76
|
+
// BlockSchemaFromSpecs<BSpecs>,
|
|
77
|
+
// InlineContentSchemaFromSpecs<ISpecs>,
|
|
78
|
+
// StyleSchemaFromSpecs<SSpecs>
|
|
79
|
+
// >;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
constructor(opts?: {
|
|
83
|
+
blockSpecs?: BlockSpecs;
|
|
84
|
+
inlineContentSpecs?: InlineContentSpecs;
|
|
85
|
+
styleSpecs?: StyleSpecs;
|
|
86
|
+
}) {
|
|
87
|
+
this.blockSpecs = opts?.blockSpecs || defaultBlockSpecs;
|
|
88
|
+
this.inlineContentSpecs =
|
|
89
|
+
opts?.inlineContentSpecs || defaultInlineContentSpecs;
|
|
90
|
+
this.styleSpecs = opts?.styleSpecs || defaultStyleSpecs;
|
|
91
|
+
|
|
92
|
+
this.blockSchema = getBlockSchemaFromSpecs(this.blockSpecs) as any;
|
|
93
|
+
this.inlineContentSchema = getInlineContentSchemaFromSpecs(
|
|
94
|
+
this.inlineContentSpecs
|
|
95
|
+
) as any;
|
|
96
|
+
this.styleSchema = getStyleSchemaFromSpecs(this.styleSpecs) as any;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { EditorOptions, createDocument } from "@tiptap/core";
|
|
2
|
+
// import "./blocknote.css";
|
|
3
|
+
import { Editor as TiptapEditor } from "@tiptap/core";
|
|
4
|
+
import { Node } from "@tiptap/pm/model";
|
|
5
|
+
import { EditorView } from "@tiptap/pm/view";
|
|
6
|
+
import { EditorState } from "prosemirror-state";
|
|
7
|
+
|
|
8
|
+
import { blockToNode } from "../api/nodeConversions/nodeConversions";
|
|
9
|
+
import { PartialBlock } from "../blocks/defaultBlocks";
|
|
10
|
+
import { StyleSchema } from "../schema";
|
|
11
|
+
|
|
12
|
+
export type BlockNoteTipTapEditorOptions = Partial<
|
|
13
|
+
Omit<EditorOptions, "content">
|
|
14
|
+
> & {
|
|
15
|
+
content: PartialBlock<any, any, any>[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Custom Editor class that extends TiptapEditor and separates
|
|
20
|
+
* the creation of the view from the constructor.
|
|
21
|
+
*/
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
export class BlockNoteTipTapEditor extends TiptapEditor {
|
|
24
|
+
private _state: EditorState;
|
|
25
|
+
|
|
26
|
+
constructor(options: BlockNoteTipTapEditorOptions, styleSchema: StyleSchema) {
|
|
27
|
+
// possible fix for next.js server side rendering
|
|
28
|
+
// const d = globalThis.document;
|
|
29
|
+
// const w = globalThis.window;
|
|
30
|
+
// if (!globalThis.document) {
|
|
31
|
+
// globalThis.document = {
|
|
32
|
+
// createElement: () => {},
|
|
33
|
+
// };
|
|
34
|
+
// }
|
|
35
|
+
// if (!globalThis.window) {
|
|
36
|
+
// globalThis.window = {
|
|
37
|
+
// setTimeout: () => {},
|
|
38
|
+
// };
|
|
39
|
+
// }
|
|
40
|
+
// options.injectCSS = false
|
|
41
|
+
super({ ...options, content: undefined });
|
|
42
|
+
|
|
43
|
+
// try {
|
|
44
|
+
// globalThis.window = w;
|
|
45
|
+
// } catch(e) {}
|
|
46
|
+
// try {
|
|
47
|
+
// globalThis.document = d;
|
|
48
|
+
// } catch(e) {}
|
|
49
|
+
|
|
50
|
+
// This is a hack to make "initial content detection" by y-prosemirror (and also tiptap isEmpty)
|
|
51
|
+
// properly detect whether or not the document has changed.
|
|
52
|
+
// We change the doc.createAndFill function to make sure the initial block id is set, instead of null
|
|
53
|
+
const schema = this.schema;
|
|
54
|
+
let cache: any;
|
|
55
|
+
const oldCreateAndFill = schema.nodes.doc.createAndFill;
|
|
56
|
+
(schema.nodes.doc as any).createAndFill = (...args: any) => {
|
|
57
|
+
if (cache) {
|
|
58
|
+
return cache;
|
|
59
|
+
}
|
|
60
|
+
const ret = oldCreateAndFill.apply(schema.nodes.doc, args);
|
|
61
|
+
|
|
62
|
+
// create a copy that we can mutate (otherwise, assigning attrs is not safe and corrupts the pm state)
|
|
63
|
+
const jsonNode = JSON.parse(JSON.stringify(ret!.toJSON()));
|
|
64
|
+
jsonNode.content[0].content[0].attrs.id = "initialBlockId";
|
|
65
|
+
|
|
66
|
+
cache = Node.fromJSON(schema, jsonNode);
|
|
67
|
+
return cache;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
let doc: Node;
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const pmNodes = options?.content.map((b) =>
|
|
74
|
+
blockToNode(b, this.schema, styleSchema).toJSON()
|
|
75
|
+
);
|
|
76
|
+
doc = createDocument(
|
|
77
|
+
{
|
|
78
|
+
type: "doc",
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "blockGroup",
|
|
82
|
+
content: pmNodes,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
this.schema,
|
|
87
|
+
this.options.parseOptions
|
|
88
|
+
);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.error(
|
|
91
|
+
"Error creating document from blocks passed as `initialContent`. Caused by exception: ",
|
|
92
|
+
e
|
|
93
|
+
);
|
|
94
|
+
throw new Error(
|
|
95
|
+
"Error creating document from blocks passed as `initialContent`:\n" +
|
|
96
|
+
+JSON.stringify(options.content)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Create state immediately, so that it's available independently from the View,
|
|
101
|
+
// the way Prosemirror "intends it to be". This also makes sure that we can access
|
|
102
|
+
// the state before the view is created / mounted.
|
|
103
|
+
this._state = EditorState.create({
|
|
104
|
+
doc,
|
|
105
|
+
schema: this.schema,
|
|
106
|
+
// selection: selection || undefined,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
get state() {
|
|
111
|
+
if (this.view) {
|
|
112
|
+
this._state = this.view.state;
|
|
113
|
+
}
|
|
114
|
+
return this._state;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
createView() {
|
|
118
|
+
// no-op
|
|
119
|
+
// Disable default call to `createView` in the Editor constructor.
|
|
120
|
+
// We should call `createView` manually only when a DOM element is available
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Replace the default `createView` method with a custom one - which we call on mount
|
|
125
|
+
*/
|
|
126
|
+
private createViewAlternative() {
|
|
127
|
+
// Without queueMicrotask, custom IC / styles will give a React FlushSync error
|
|
128
|
+
queueMicrotask(() => {
|
|
129
|
+
this.view = new EditorView(this.options.element, {
|
|
130
|
+
...this.options.editorProps,
|
|
131
|
+
// @ts-ignore
|
|
132
|
+
dispatchTransaction: this.dispatchTransaction.bind(this),
|
|
133
|
+
state: this.state,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// `editor.view` is not yet available at this time.
|
|
137
|
+
// Therefore we will add all plugins and node views directly afterwards.
|
|
138
|
+
const newState = this.state.reconfigure({
|
|
139
|
+
plugins: this.extensionManager.plugins,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
this.view.updateState(newState);
|
|
143
|
+
|
|
144
|
+
this.createNodeViews();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Mounts / unmounts the editor to a dom element
|
|
150
|
+
*
|
|
151
|
+
* @param element DOM element to mount to, ur null / undefined to destroy
|
|
152
|
+
*/
|
|
153
|
+
public mount = (element?: HTMLElement | null) => {
|
|
154
|
+
if (!element) {
|
|
155
|
+
this.destroy();
|
|
156
|
+
} else {
|
|
157
|
+
this.options.element = element;
|
|
158
|
+
// @ts-ignore
|
|
159
|
+
this.createViewAlternative();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
BlockSchema,
|
|
4
|
-
InlineContentSchema,
|
|
5
|
-
StyleSchema,
|
|
6
|
-
} from "../schema";
|
|
1
|
+
import { Block } from "../blocks/defaultBlocks";
|
|
2
|
+
import { BlockSchema, InlineContentSchema, StyleSchema } from "../schema";
|
|
7
3
|
|
|
8
4
|
export type TextCursorPosition<
|
|
9
5
|
BSchema extends BlockSchema,
|
package/src/editor/editor.css
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
BlockSchema,
|
|
4
|
-
InlineContentSchema,
|
|
5
|
-
StyleSchema,
|
|
6
|
-
} from "../schema";
|
|
1
|
+
import { Block } from "../blocks/defaultBlocks";
|
|
2
|
+
import { BlockSchema, InlineContentSchema, StyleSchema } from "../schema";
|
|
7
3
|
|
|
8
4
|
export type Selection<
|
|
9
5
|
BSchema extends BlockSchema,
|
|
@@ -3,20 +3,15 @@ import { EditorState, Plugin, PluginKey } from "prosemirror-state";
|
|
|
3
3
|
import { EditorView } from "prosemirror-view";
|
|
4
4
|
|
|
5
5
|
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
|
|
6
|
-
import {
|
|
7
|
-
BaseUiElementCallbacks,
|
|
8
|
-
BaseUiElementState,
|
|
9
|
-
} from "../../extensions-shared/BaseUiElementTypes";
|
|
6
|
+
import { UiElementPosition } from "../../extensions-shared/UiElementPosition";
|
|
10
7
|
import { BlockSchema, InlineContentSchema, StyleSchema } from "../../schema";
|
|
11
8
|
import { EventEmitter } from "../../util/EventEmitter";
|
|
12
9
|
|
|
13
|
-
export type
|
|
14
|
-
|
|
15
|
-
export type FormattingToolbarState = BaseUiElementState;
|
|
10
|
+
export type FormattingToolbarState = UiElementPosition;
|
|
16
11
|
|
|
17
12
|
export class FormattingToolbarView {
|
|
18
|
-
|
|
19
|
-
public
|
|
13
|
+
public state?: FormattingToolbarState;
|
|
14
|
+
public emitUpdate: () => void;
|
|
20
15
|
|
|
21
16
|
public preventHide = false;
|
|
22
17
|
public preventShow = false;
|
|
@@ -36,18 +31,16 @@ export class FormattingToolbarView {
|
|
|
36
31
|
StyleSchema
|
|
37
32
|
>,
|
|
38
33
|
private readonly pmView: EditorView,
|
|
39
|
-
|
|
40
|
-
formattingToolbarState: FormattingToolbarState
|
|
41
|
-
) => void
|
|
34
|
+
emitUpdate: (state: FormattingToolbarState) => void
|
|
42
35
|
) {
|
|
43
|
-
this.
|
|
44
|
-
if (!this.
|
|
36
|
+
this.emitUpdate = () => {
|
|
37
|
+
if (!this.state) {
|
|
45
38
|
throw new Error(
|
|
46
39
|
"Attempting to update uninitialized formatting toolbar"
|
|
47
40
|
);
|
|
48
41
|
}
|
|
49
42
|
|
|
50
|
-
|
|
43
|
+
emitUpdate(this.state);
|
|
51
44
|
};
|
|
52
45
|
|
|
53
46
|
pmView.dom.addEventListener("mousedown", this.viewMousedownHandler);
|
|
@@ -72,9 +65,9 @@ export class FormattingToolbarView {
|
|
|
72
65
|
|
|
73
66
|
// For dragging the whole editor.
|
|
74
67
|
dragHandler = () => {
|
|
75
|
-
if (this.
|
|
76
|
-
this.
|
|
77
|
-
this.
|
|
68
|
+
if (this.state?.show) {
|
|
69
|
+
this.state.show = false;
|
|
70
|
+
this.emitUpdate();
|
|
78
71
|
}
|
|
79
72
|
};
|
|
80
73
|
|
|
@@ -105,16 +98,16 @@ export class FormattingToolbarView {
|
|
|
105
98
|
return;
|
|
106
99
|
}
|
|
107
100
|
|
|
108
|
-
if (this.
|
|
109
|
-
this.
|
|
110
|
-
this.
|
|
101
|
+
if (this.state?.show) {
|
|
102
|
+
this.state.show = false;
|
|
103
|
+
this.emitUpdate();
|
|
111
104
|
}
|
|
112
105
|
};
|
|
113
106
|
|
|
114
107
|
scrollHandler = () => {
|
|
115
|
-
if (this.
|
|
116
|
-
this.
|
|
117
|
-
this.
|
|
108
|
+
if (this.state?.show) {
|
|
109
|
+
this.state.referencePos = this.getSelectionBoundingBox();
|
|
110
|
+
this.emitUpdate();
|
|
118
111
|
}
|
|
119
112
|
};
|
|
120
113
|
|
|
@@ -152,24 +145,24 @@ export class FormattingToolbarView {
|
|
|
152
145
|
!this.preventShow &&
|
|
153
146
|
(shouldShow || this.preventHide)
|
|
154
147
|
) {
|
|
155
|
-
this.
|
|
148
|
+
this.state = {
|
|
156
149
|
show: true,
|
|
157
150
|
referencePos: this.getSelectionBoundingBox(),
|
|
158
151
|
};
|
|
159
152
|
|
|
160
|
-
this.
|
|
153
|
+
this.emitUpdate();
|
|
161
154
|
|
|
162
155
|
return;
|
|
163
156
|
}
|
|
164
157
|
|
|
165
158
|
// Checks if menu should be hidden.
|
|
166
159
|
if (
|
|
167
|
-
this.
|
|
160
|
+
this.state?.show &&
|
|
168
161
|
!this.preventHide &&
|
|
169
162
|
(!shouldShow || this.preventShow || !this.editor.isEditable)
|
|
170
163
|
) {
|
|
171
|
-
this.
|
|
172
|
-
this.
|
|
164
|
+
this.state.show = false;
|
|
165
|
+
this.emitUpdate();
|
|
173
166
|
|
|
174
167
|
return;
|
|
175
168
|
}
|
|
@@ -1,51 +1,44 @@
|
|
|
1
1
|
import { EditorState, Plugin, PluginKey } from "prosemirror-state";
|
|
2
2
|
import { EditorView } from "prosemirror-view";
|
|
3
3
|
|
|
4
|
-
import { EventEmitter } from "../../util/EventEmitter";
|
|
5
4
|
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
|
|
6
|
-
import {
|
|
7
|
-
|
|
5
|
+
import type {
|
|
6
|
+
BlockFromConfig,
|
|
8
7
|
InlineContentSchema,
|
|
9
|
-
SpecificBlock,
|
|
10
8
|
StyleSchema,
|
|
11
9
|
} from "../../schema";
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export type
|
|
17
|
-
|
|
18
|
-
export type ImageToolbarState<
|
|
19
|
-
B extends BlockSchema,
|
|
10
|
+
import { UiElementPosition } from "../../extensions-shared/UiElementPosition";
|
|
11
|
+
import { EventEmitter } from "../../util/EventEmitter";
|
|
12
|
+
import { DefaultBlockSchema } from "../../blocks/defaultBlocks";
|
|
13
|
+
|
|
14
|
+
export type ImagePanelState<
|
|
20
15
|
I extends InlineContentSchema,
|
|
21
|
-
S extends StyleSchema
|
|
22
|
-
> =
|
|
23
|
-
|
|
16
|
+
S extends StyleSchema
|
|
17
|
+
> = UiElementPosition & {
|
|
18
|
+
// TODO: This typing is not quite right (children should be from BSchema)
|
|
19
|
+
block: BlockFromConfig<DefaultBlockSchema["image"], I, S>;
|
|
24
20
|
};
|
|
25
21
|
|
|
26
|
-
export class
|
|
27
|
-
BSchema extends BlockSchema,
|
|
22
|
+
export class ImagePanelView<
|
|
28
23
|
I extends InlineContentSchema,
|
|
29
24
|
S extends StyleSchema
|
|
30
25
|
> {
|
|
31
|
-
|
|
32
|
-
public
|
|
26
|
+
public state?: ImagePanelState<I, S>;
|
|
27
|
+
public emitUpdate: () => void;
|
|
33
28
|
|
|
34
29
|
public prevWasEditable: boolean | null = null;
|
|
35
30
|
|
|
36
31
|
constructor(
|
|
37
32
|
private readonly pluginKey: PluginKey,
|
|
38
33
|
private readonly pmView: EditorView,
|
|
39
|
-
|
|
40
|
-
imageToolbarState: ImageToolbarState<BSchema, I, S>
|
|
41
|
-
) => void
|
|
34
|
+
emitUpdate: (state: ImagePanelState<I, S>) => void
|
|
42
35
|
) {
|
|
43
|
-
this.
|
|
44
|
-
if (!this.
|
|
45
|
-
throw new Error("Attempting to update uninitialized image
|
|
36
|
+
this.emitUpdate = () => {
|
|
37
|
+
if (!this.state) {
|
|
38
|
+
throw new Error("Attempting to update uninitialized image panel");
|
|
46
39
|
}
|
|
47
40
|
|
|
48
|
-
|
|
41
|
+
emitUpdate(this.state);
|
|
49
42
|
};
|
|
50
43
|
|
|
51
44
|
pmView.dom.addEventListener("mousedown", this.mouseDownHandler);
|
|
@@ -58,17 +51,17 @@ export class ImageToolbarView<
|
|
|
58
51
|
}
|
|
59
52
|
|
|
60
53
|
mouseDownHandler = () => {
|
|
61
|
-
if (this.
|
|
62
|
-
this.
|
|
63
|
-
this.
|
|
54
|
+
if (this.state?.show) {
|
|
55
|
+
this.state.show = false;
|
|
56
|
+
this.emitUpdate();
|
|
64
57
|
}
|
|
65
58
|
};
|
|
66
59
|
|
|
67
60
|
// For dragging the whole editor.
|
|
68
61
|
dragstartHandler = () => {
|
|
69
|
-
if (this.
|
|
70
|
-
this.
|
|
71
|
-
this.
|
|
62
|
+
if (this.state?.show) {
|
|
63
|
+
this.state.show = false;
|
|
64
|
+
this.emitUpdate();
|
|
72
65
|
}
|
|
73
66
|
};
|
|
74
67
|
|
|
@@ -76,7 +69,7 @@ export class ImageToolbarView<
|
|
|
76
69
|
const editorWrapper = this.pmView.dom.parentElement!;
|
|
77
70
|
|
|
78
71
|
// Checks if the focus is moving to an element outside the editor. If it is,
|
|
79
|
-
// the
|
|
72
|
+
// the panel is hidden.
|
|
80
73
|
if (
|
|
81
74
|
// An element is clicked.
|
|
82
75
|
event &&
|
|
@@ -88,41 +81,40 @@ export class ImageToolbarView<
|
|
|
88
81
|
return;
|
|
89
82
|
}
|
|
90
83
|
|
|
91
|
-
if (this.
|
|
92
|
-
this.
|
|
93
|
-
this.
|
|
84
|
+
if (this.state?.show) {
|
|
85
|
+
this.state.show = false;
|
|
86
|
+
this.emitUpdate();
|
|
94
87
|
}
|
|
95
88
|
};
|
|
96
89
|
|
|
97
90
|
scrollHandler = () => {
|
|
98
|
-
if (this.
|
|
91
|
+
if (this.state?.show) {
|
|
99
92
|
const blockElement = document.querySelector(
|
|
100
|
-
`[data-node-type="blockContainer"][data-id="${this.
|
|
93
|
+
`[data-node-type="blockContainer"][data-id="${this.state.block.id}"]`
|
|
101
94
|
)!;
|
|
102
95
|
|
|
103
|
-
this.
|
|
104
|
-
|
|
105
|
-
this.updateImageToolbar();
|
|
96
|
+
this.state.referencePos = blockElement.getBoundingClientRect();
|
|
97
|
+
this.emitUpdate();
|
|
106
98
|
}
|
|
107
99
|
};
|
|
108
100
|
|
|
109
101
|
update(view: EditorView, prevState: EditorState) {
|
|
110
102
|
const pluginState: {
|
|
111
|
-
block:
|
|
103
|
+
block: BlockFromConfig<DefaultBlockSchema["image"], I, S>;
|
|
112
104
|
} = this.pluginKey.getState(view.state);
|
|
113
105
|
|
|
114
|
-
if (!this.
|
|
106
|
+
if (!this.state?.show && pluginState.block) {
|
|
115
107
|
const blockElement = document.querySelector(
|
|
116
108
|
`[data-node-type="blockContainer"][data-id="${pluginState.block.id}"]`
|
|
117
109
|
)!;
|
|
118
110
|
|
|
119
|
-
this.
|
|
111
|
+
this.state = {
|
|
120
112
|
show: true,
|
|
121
113
|
referencePos: blockElement.getBoundingClientRect(),
|
|
122
114
|
block: pluginState.block,
|
|
123
115
|
};
|
|
124
116
|
|
|
125
|
-
this.
|
|
117
|
+
this.emitUpdate();
|
|
126
118
|
|
|
127
119
|
return;
|
|
128
120
|
}
|
|
@@ -131,10 +123,10 @@ export class ImageToolbarView<
|
|
|
131
123
|
!view.state.selection.eq(prevState.selection) ||
|
|
132
124
|
!view.state.doc.eq(prevState.doc)
|
|
133
125
|
) {
|
|
134
|
-
if (this.
|
|
135
|
-
this.
|
|
126
|
+
if (this.state?.show) {
|
|
127
|
+
this.state.show = false;
|
|
136
128
|
|
|
137
|
-
this.
|
|
129
|
+
this.emitUpdate();
|
|
138
130
|
}
|
|
139
131
|
}
|
|
140
132
|
}
|
|
@@ -150,26 +142,27 @@ export class ImageToolbarView<
|
|
|
150
142
|
}
|
|
151
143
|
}
|
|
152
144
|
|
|
153
|
-
|
|
145
|
+
const imagePanelPluginKey = new PluginKey("ImagePanelPlugin");
|
|
154
146
|
|
|
155
|
-
export class
|
|
156
|
-
BSchema extends BlockSchema,
|
|
147
|
+
export class ImagePanelProsemirrorPlugin<
|
|
157
148
|
I extends InlineContentSchema,
|
|
158
149
|
S extends StyleSchema
|
|
159
150
|
> extends EventEmitter<any> {
|
|
160
|
-
private view:
|
|
151
|
+
private view: ImagePanelView<I, S> | undefined;
|
|
161
152
|
public readonly plugin: Plugin;
|
|
162
153
|
|
|
163
|
-
constructor(
|
|
154
|
+
constructor(
|
|
155
|
+
_editor: BlockNoteEditor<{ image: DefaultBlockSchema["image"] }, I, S>
|
|
156
|
+
) {
|
|
164
157
|
super();
|
|
165
158
|
this.plugin = new Plugin<{
|
|
166
|
-
block:
|
|
159
|
+
block: BlockFromConfig<DefaultBlockSchema["image"], I, S> | undefined;
|
|
167
160
|
}>({
|
|
168
|
-
key:
|
|
161
|
+
key: imagePanelPluginKey,
|
|
169
162
|
view: (editorView) => {
|
|
170
|
-
this.view = new
|
|
163
|
+
this.view = new ImagePanelView(
|
|
171
164
|
// editor,
|
|
172
|
-
|
|
165
|
+
imagePanelPluginKey,
|
|
173
166
|
editorView,
|
|
174
167
|
(state) => {
|
|
175
168
|
this.emit("update", state);
|
|
@@ -184,8 +177,9 @@ export class ImageToolbarProsemirrorPlugin<
|
|
|
184
177
|
};
|
|
185
178
|
},
|
|
186
179
|
apply: (transaction) => {
|
|
187
|
-
const block:
|
|
188
|
-
|
|
180
|
+
const block:
|
|
181
|
+
| BlockFromConfig<DefaultBlockSchema["image"], I, S>
|
|
182
|
+
| undefined = transaction.getMeta(imagePanelPluginKey)?.block;
|
|
189
183
|
|
|
190
184
|
return {
|
|
191
185
|
block,
|
|
@@ -195,7 +189,7 @@ export class ImageToolbarProsemirrorPlugin<
|
|
|
195
189
|
});
|
|
196
190
|
}
|
|
197
191
|
|
|
198
|
-
public onUpdate(callback: (state:
|
|
192
|
+
public onUpdate(callback: (state: ImagePanelState<I, S>) => void) {
|
|
199
193
|
return this.on("update", callback);
|
|
200
194
|
}
|
|
201
195
|
}
|