@blocknote/core 0.9.0 → 0.9.2
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 +337 -298
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +5 -4
- package/dist/blocknote.umd.cjs.map +1 -1
- package/package.json +2 -2
- package/src/BlockNoteEditor.ts +2 -2
- package/src/BlockNoteExtensions.ts +24 -22
- package/src/api/blockManipulation/blockManipulation.test.ts +2 -2
- package/src/api/blockManipulation/blockManipulation.ts +1 -1
- package/src/api/formatConversions/formatConversions.test.ts +2 -2
- package/src/api/formatConversions/formatConversions.ts +47 -3
- package/src/api/nodeConversions/nodeConversions.test.ts +6 -6
- package/src/api/nodeConversions/nodeConversions.ts +6 -6
- package/src/extensions/Blocks/PreviousBlockTypePlugin.ts +2 -2
- package/src/extensions/Blocks/helpers/getBlockInfoFromPos.ts +27 -5
- package/src/extensions/Blocks/nodes/BlockContainer.ts +5 -5
- package/src/extensions/SideMenu/MultipleNodeSelection.ts +3 -3
- package/src/extensions/SideMenu/SideMenuPlugin.ts +9 -9
- package/src/extensions/UniqueID/UniqueID.ts +10 -9
- package/src/shared/EventEmitter.ts +1 -0
- package/src/shared/plugins/suggestion/SuggestionPlugin.ts +6 -2
- package/types/src/extensions/Blocks/helpers/getBlockInfoFromPos.d.ts +9 -1
- package/types/src/extensions/Blocks/nodes/TableCell.d.ts +5 -0
- package/types/src/extensions/Blocks/nodes/TableRow.d.ts +5 -0
- package/types/src/extensions/SideMenu/MultipleNodeSelection.d.ts +1 -1
- package/types/src/EventEmitter.d.ts +0 -11
- package/types/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.d.ts +0 -0
- package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +0 -16
- package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +0 -55
- package/types/src/extensions/DraggableBlocks/MultipleNodeSelection.d.ts +0 -24
- package/types/src/extensions/FormattingToolbar/FormattingToolbarExtension.d.ts +0 -11
- package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +0 -10
- package/types/src/extensions/HyperlinkToolbar/HyperlinkMark.d.ts +0 -8
- package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.d.ts +0 -0
- package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +0 -13
- package/types/src/extensions/SlashMenu/index.d.ts +0 -3
- package/types/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.d.ts +0 -12
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"homepage": "https://github.com/TypeCellOS/BlockNote",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
|
-
"version": "0.9.
|
|
6
|
+
"version": "0.9.2",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
9
|
"types",
|
|
@@ -109,5 +109,5 @@
|
|
|
109
109
|
"access": "public",
|
|
110
110
|
"registry": "https://registry.npmjs.org/"
|
|
111
111
|
},
|
|
112
|
-
"gitHead": "
|
|
112
|
+
"gitHead": "4d18bc8a01e841954672b9e522f20ce12f4ada10"
|
|
113
113
|
}
|
package/src/BlockNoteEditor.ts
CHANGED
|
@@ -353,7 +353,7 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
|
|
|
353
353
|
*/
|
|
354
354
|
public forEachBlock(
|
|
355
355
|
callback: (block: Block<BSchema>) => boolean,
|
|
356
|
-
reverse
|
|
356
|
+
reverse = false
|
|
357
357
|
): void {
|
|
358
358
|
const blocks = this.topLevelBlocks.slice();
|
|
359
359
|
|
|
@@ -692,7 +692,7 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
|
|
|
692
692
|
return;
|
|
693
693
|
}
|
|
694
694
|
|
|
695
|
-
|
|
695
|
+
const { from, to } = this._tiptapEditor.state.selection;
|
|
696
696
|
|
|
697
697
|
if (!text) {
|
|
698
698
|
text = this._tiptapEditor.state.doc.textBetween(from, to);
|
|
@@ -118,32 +118,34 @@ export const getBlockNoteExtensions = <BSchema extends BlockSchema>(opts: {
|
|
|
118
118
|
fragment: opts.collaboration.fragment,
|
|
119
119
|
})
|
|
120
120
|
);
|
|
121
|
-
|
|
122
|
-
const
|
|
121
|
+
if (opts.collaboration.provider?.awareness) {
|
|
122
|
+
const defaultRender = (user: { color: string; name: string }) => {
|
|
123
|
+
const cursor = document.createElement("span");
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
cursor.classList.add(styles["collaboration-cursor__caret"]);
|
|
126
|
+
cursor.setAttribute("style", `border-color: ${user.color}`);
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
const label = document.createElement("span");
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
label.classList.add(styles["collaboration-cursor__label"]);
|
|
131
|
+
label.setAttribute("style", `background-color: ${user.color}`);
|
|
132
|
+
label.insertBefore(document.createTextNode(user.name), null);
|
|
132
133
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
134
|
+
const nonbreakingSpace1 = document.createTextNode("\u2060");
|
|
135
|
+
const nonbreakingSpace2 = document.createTextNode("\u2060");
|
|
136
|
+
cursor.insertBefore(nonbreakingSpace1, null);
|
|
137
|
+
cursor.insertBefore(label, null);
|
|
138
|
+
cursor.insertBefore(nonbreakingSpace2, null);
|
|
139
|
+
return cursor;
|
|
140
|
+
};
|
|
141
|
+
ret.push(
|
|
142
|
+
CollaborationCursor.configure({
|
|
143
|
+
user: opts.collaboration.user,
|
|
144
|
+
render: opts.collaboration.renderCursor || defaultRender,
|
|
145
|
+
provider: opts.collaboration.provider,
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
}
|
|
147
149
|
} else {
|
|
148
150
|
// disable history extension when collaboration is enabled as Yjs takes care of undo / redo
|
|
149
151
|
ret.push(History);
|
|
@@ -24,7 +24,7 @@ let insert: (
|
|
|
24
24
|
) => Block<DefaultBlockSchema>[];
|
|
25
25
|
|
|
26
26
|
beforeEach(() => {
|
|
27
|
-
(window as Window & { __TEST_OPTIONS?:
|
|
27
|
+
(window as Window & { __TEST_OPTIONS?: any }).__TEST_OPTIONS = {};
|
|
28
28
|
|
|
29
29
|
editor = new BlockNoteEditor();
|
|
30
30
|
|
|
@@ -80,7 +80,7 @@ afterEach(() => {
|
|
|
80
80
|
editor._tiptapEditor.destroy();
|
|
81
81
|
editor = undefined as any;
|
|
82
82
|
|
|
83
|
-
delete (window as Window & { __TEST_OPTIONS?:
|
|
83
|
+
delete (window as Window & { __TEST_OPTIONS?: any }).__TEST_OPTIONS;
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
describe("Inserting Blocks with Different Placements", () => {
|
|
@@ -107,7 +107,7 @@ export function removeBlocks(
|
|
|
107
107
|
});
|
|
108
108
|
|
|
109
109
|
if (idsOfBlocksToRemove.size > 0) {
|
|
110
|
-
|
|
110
|
+
const notFoundIds = [...idsOfBlocksToRemove].join("\n");
|
|
111
111
|
|
|
112
112
|
throw Error(
|
|
113
113
|
"Blocks with the following IDs could not be found in the editor: " +
|
|
@@ -579,7 +579,7 @@ function removeInlineContentClass(html: string) {
|
|
|
579
579
|
}
|
|
580
580
|
|
|
581
581
|
beforeEach(() => {
|
|
582
|
-
(window as Window & { __TEST_OPTIONS?:
|
|
582
|
+
(window as Window & { __TEST_OPTIONS?: any }).__TEST_OPTIONS = {};
|
|
583
583
|
|
|
584
584
|
editor = new BlockNoteEditor();
|
|
585
585
|
});
|
|
@@ -588,7 +588,7 @@ afterEach(() => {
|
|
|
588
588
|
editor._tiptapEditor.destroy();
|
|
589
589
|
editor = undefined as any;
|
|
590
590
|
|
|
591
|
-
delete (window as Window & { __TEST_OPTIONS?:
|
|
591
|
+
delete (window as Window & { __TEST_OPTIONS?: any }).__TEST_OPTIONS;
|
|
592
592
|
});
|
|
593
593
|
|
|
594
594
|
describe("Non-Nested Block/HTML/Markdown Conversions", () => {
|
|
@@ -4,7 +4,7 @@ import rehypeRemark from "rehype-remark";
|
|
|
4
4
|
import rehypeStringify from "rehype-stringify";
|
|
5
5
|
import remarkGfm from "remark-gfm";
|
|
6
6
|
import remarkParse from "remark-parse";
|
|
7
|
-
import remarkRehype from "remark-rehype";
|
|
7
|
+
import remarkRehype, { defaultHandlers } from "remark-rehype";
|
|
8
8
|
import remarkStringify from "remark-stringify";
|
|
9
9
|
import { unified } from "unified";
|
|
10
10
|
import { Block, BlockSchema } from "../../extensions/Blocks/api/blockTypes";
|
|
@@ -47,7 +47,7 @@ export async function HTMLToBlocks<BSchema extends BlockSchema>(
|
|
|
47
47
|
htmlNode.innerHTML = html.trim();
|
|
48
48
|
|
|
49
49
|
const parser = DOMParser.fromSchema(schema);
|
|
50
|
-
const parentNode = parser.parse(htmlNode);
|
|
50
|
+
const parentNode = parser.parse(htmlNode); //, { preserveWhitespace: "full" });
|
|
51
51
|
|
|
52
52
|
const blocks: Block<BSchema>[] = [];
|
|
53
53
|
|
|
@@ -73,6 +73,45 @@ export async function blocksToMarkdown<BSchema extends BlockSchema>(
|
|
|
73
73
|
return markdownString.value as string;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// modefied version of https://github.com/syntax-tree/mdast-util-to-hast/blob/main/lib/handlers/code.js
|
|
77
|
+
// that outputs a data-language attribute instead of a CSS class (e.g.: language-typescript)
|
|
78
|
+
function code(state: any, node: any) {
|
|
79
|
+
const value = node.value ? node.value + "\n" : "";
|
|
80
|
+
/** @type {Properties} */
|
|
81
|
+
const properties: any = {};
|
|
82
|
+
|
|
83
|
+
if (node.lang) {
|
|
84
|
+
// changed line
|
|
85
|
+
properties["data-language"] = node.lang;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Create `<code>`.
|
|
89
|
+
/** @type {Element} */
|
|
90
|
+
let result: any = {
|
|
91
|
+
type: "element",
|
|
92
|
+
tagName: "code",
|
|
93
|
+
properties,
|
|
94
|
+
children: [{ type: "text", value }],
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
if (node.meta) {
|
|
98
|
+
result.data = { meta: node.meta };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
state.patch(node, result);
|
|
102
|
+
result = state.applyData(node, result);
|
|
103
|
+
|
|
104
|
+
// Create `<pre>`.
|
|
105
|
+
result = {
|
|
106
|
+
type: "element",
|
|
107
|
+
tagName: "pre",
|
|
108
|
+
properties: {},
|
|
109
|
+
children: [result],
|
|
110
|
+
};
|
|
111
|
+
state.patch(node, result);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
76
115
|
export async function markdownToBlocks<BSchema extends BlockSchema>(
|
|
77
116
|
markdown: string,
|
|
78
117
|
blockSchema: BSchema,
|
|
@@ -81,7 +120,12 @@ export async function markdownToBlocks<BSchema extends BlockSchema>(
|
|
|
81
120
|
const htmlString = await unified()
|
|
82
121
|
.use(remarkParse)
|
|
83
122
|
.use(remarkGfm)
|
|
84
|
-
.use(remarkRehype
|
|
123
|
+
.use(remarkRehype, {
|
|
124
|
+
handlers: {
|
|
125
|
+
...(defaultHandlers as any),
|
|
126
|
+
code,
|
|
127
|
+
},
|
|
128
|
+
})
|
|
85
129
|
.use(rehypeStringify)
|
|
86
130
|
.process(markdown);
|
|
87
131
|
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { Editor } from "@tiptap/core";
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
3
|
import { BlockNoteEditor, PartialBlock } from "../..";
|
|
4
|
-
import UniqueID from "../../extensions/UniqueID/UniqueID";
|
|
5
|
-
import { blockToNode, nodeToBlock } from "./nodeConversions";
|
|
6
|
-
import { partialBlockToBlockForTesting } from "./testUtil";
|
|
7
4
|
import {
|
|
8
|
-
defaultBlockSchema,
|
|
9
5
|
DefaultBlockSchema,
|
|
6
|
+
defaultBlockSchema,
|
|
10
7
|
} from "../../extensions/Blocks/api/defaultBlocks";
|
|
8
|
+
import UniqueID from "../../extensions/UniqueID/UniqueID";
|
|
9
|
+
import { blockToNode, nodeToBlock } from "./nodeConversions";
|
|
10
|
+
import { partialBlockToBlockForTesting } from "./testUtil";
|
|
11
11
|
|
|
12
12
|
let editor: BlockNoteEditor;
|
|
13
13
|
let tt: Editor;
|
|
14
14
|
|
|
15
15
|
beforeEach(() => {
|
|
16
|
-
(window as Window & { __TEST_OPTIONS?:
|
|
16
|
+
(window as Window & { __TEST_OPTIONS?: any }).__TEST_OPTIONS = {};
|
|
17
17
|
|
|
18
18
|
editor = new BlockNoteEditor();
|
|
19
19
|
tt = editor._tiptapEditor;
|
|
@@ -24,7 +24,7 @@ afterEach(() => {
|
|
|
24
24
|
editor = undefined as any;
|
|
25
25
|
tt = undefined as any;
|
|
26
26
|
|
|
27
|
-
delete (window as Window & { __TEST_OPTIONS?:
|
|
27
|
+
delete (window as Window & { __TEST_OPTIONS?: any }).__TEST_OPTIONS;
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
describe("Simple ProseMirror Node Conversions", () => {
|
|
@@ -16,9 +16,9 @@ import {
|
|
|
16
16
|
Styles,
|
|
17
17
|
ToggledStyle,
|
|
18
18
|
} from "../../extensions/Blocks/api/inlineContentTypes";
|
|
19
|
-
import { getBlockInfoFromPos } from "../../extensions/Blocks/helpers/getBlockInfoFromPos";
|
|
20
19
|
import UniqueID from "../../extensions/UniqueID/UniqueID";
|
|
21
20
|
import { UnreachableCaseError } from "../../shared/utils";
|
|
21
|
+
import { getBlockInfo } from "../../extensions/Blocks/helpers/getBlockInfoFromPos";
|
|
22
22
|
|
|
23
23
|
const toggleStyles = new Set<ToggledStyle>([
|
|
24
24
|
"bold",
|
|
@@ -91,7 +91,7 @@ function styledTextArrayToNodes(
|
|
|
91
91
|
content: string | StyledText[],
|
|
92
92
|
schema: Schema
|
|
93
93
|
): Node[] {
|
|
94
|
-
|
|
94
|
+
const nodes: Node[] = [];
|
|
95
95
|
|
|
96
96
|
if (typeof content === "string") {
|
|
97
97
|
nodes.push(
|
|
@@ -113,7 +113,7 @@ export function inlineContentToNodes(
|
|
|
113
113
|
blockContent: PartialInlineContent[],
|
|
114
114
|
schema: Schema
|
|
115
115
|
): Node[] {
|
|
116
|
-
|
|
116
|
+
const nodes: Node[] = [];
|
|
117
117
|
|
|
118
118
|
for (const content of blockContent) {
|
|
119
119
|
if (content.type === "link") {
|
|
@@ -369,7 +369,7 @@ export function nodeToBlock<BSchema extends BlockSchema>(
|
|
|
369
369
|
return cachedBlock;
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
-
const blockInfo =
|
|
372
|
+
const blockInfo = getBlockInfo(node);
|
|
373
373
|
|
|
374
374
|
let id = blockInfo.id;
|
|
375
375
|
|
|
@@ -380,7 +380,7 @@ export function nodeToBlock<BSchema extends BlockSchema>(
|
|
|
380
380
|
|
|
381
381
|
const props: any = {};
|
|
382
382
|
for (const [attr, value] of Object.entries({
|
|
383
|
-
...
|
|
383
|
+
...node.attrs,
|
|
384
384
|
...blockInfo.contentNode.attrs,
|
|
385
385
|
})) {
|
|
386
386
|
const blockSpec = blockSchema[blockInfo.contentType.name];
|
|
@@ -414,7 +414,7 @@ export function nodeToBlock<BSchema extends BlockSchema>(
|
|
|
414
414
|
const children: Block<BSchema>[] = [];
|
|
415
415
|
for (let i = 0; i < blockInfo.numChildBlocks; i++) {
|
|
416
416
|
children.push(
|
|
417
|
-
nodeToBlock(
|
|
417
|
+
nodeToBlock(node.lastChild!.child(i), blockSchema, blockCache)
|
|
418
418
|
);
|
|
419
419
|
}
|
|
420
420
|
|
|
@@ -96,7 +96,7 @@ export const PreviousBlockTypePlugin = () => {
|
|
|
96
96
|
const newNodes = findChildren(newState.doc, (node) => node.attrs.id);
|
|
97
97
|
|
|
98
98
|
// Traverses all block containers in the new editor state.
|
|
99
|
-
for (
|
|
99
|
+
for (const node of newNodes) {
|
|
100
100
|
const oldNode = oldNodesById.get(node.node.attrs.id);
|
|
101
101
|
|
|
102
102
|
const oldContentNode = oldNode?.node.firstChild;
|
|
@@ -192,7 +192,7 @@ export const PreviousBlockTypePlugin = () => {
|
|
|
192
192
|
pluginState.currentTransactionOldBlockAttrs[node.attrs.id];
|
|
193
193
|
const decorationAttrs: any = {};
|
|
194
194
|
|
|
195
|
-
for (
|
|
195
|
+
for (const [nodeAttr, val] of Object.entries(prevAttrs)) {
|
|
196
196
|
decorationAttrs["data-prev-" + nodeAttributes[nodeAttr]] =
|
|
197
197
|
val || "none";
|
|
198
198
|
}
|
|
@@ -1,16 +1,40 @@
|
|
|
1
1
|
import { Node, NodeType } from "prosemirror-model";
|
|
2
2
|
|
|
3
|
-
export type
|
|
3
|
+
export type BlockInfoWithoutPositions = {
|
|
4
4
|
id: string;
|
|
5
5
|
node: Node;
|
|
6
6
|
contentNode: Node;
|
|
7
7
|
contentType: NodeType;
|
|
8
8
|
numChildBlocks: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type BlockInfo = BlockInfoWithoutPositions & {
|
|
9
12
|
startPos: number;
|
|
10
13
|
endPos: number;
|
|
11
14
|
depth: number;
|
|
12
15
|
};
|
|
13
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Helper function for `getBlockInfoFromPos`, returns information regarding
|
|
19
|
+
* provided blockContainer node.
|
|
20
|
+
* @param blockContainer The blockContainer node to retrieve info for.
|
|
21
|
+
*/
|
|
22
|
+
export function getBlockInfo(blockContainer: Node): BlockInfoWithoutPositions {
|
|
23
|
+
const id = blockContainer.attrs["id"];
|
|
24
|
+
const contentNode = blockContainer.firstChild!;
|
|
25
|
+
const contentType = contentNode.type;
|
|
26
|
+
const numChildBlocks =
|
|
27
|
+
blockContainer.childCount === 2 ? blockContainer.lastChild!.childCount : 0;
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
id,
|
|
31
|
+
node: blockContainer,
|
|
32
|
+
contentNode,
|
|
33
|
+
contentType,
|
|
34
|
+
numChildBlocks,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
14
38
|
/**
|
|
15
39
|
* Retrieves information regarding the nearest blockContainer node in a
|
|
16
40
|
* ProseMirror doc, relative to a position.
|
|
@@ -56,6 +80,7 @@ export function getBlockInfoFromPos(doc: Node, pos: number): BlockInfo {
|
|
|
56
80
|
let node = $pos.node(maxDepth);
|
|
57
81
|
let depth = maxDepth;
|
|
58
82
|
|
|
83
|
+
// eslint-disable-next-line no-constant-condition
|
|
59
84
|
while (true) {
|
|
60
85
|
if (depth < 0) {
|
|
61
86
|
throw new Error(
|
|
@@ -71,10 +96,7 @@ export function getBlockInfoFromPos(doc: Node, pos: number): BlockInfo {
|
|
|
71
96
|
node = $pos.node(depth);
|
|
72
97
|
}
|
|
73
98
|
|
|
74
|
-
const id = node
|
|
75
|
-
const contentNode = node.firstChild!;
|
|
76
|
-
const contentType = contentNode.type;
|
|
77
|
-
const numChildBlocks = node.childCount === 2 ? node.lastChild!.childCount : 0;
|
|
99
|
+
const { id, contentNode, contentType, numChildBlocks } = getBlockInfo(node);
|
|
78
100
|
|
|
79
101
|
const startPos = $pos.start(depth);
|
|
80
102
|
const endPos = $pos.end(depth);
|
|
@@ -6,15 +6,15 @@ import {
|
|
|
6
6
|
inlineContentToNodes,
|
|
7
7
|
} from "../../../api/nodeConversions/nodeConversions";
|
|
8
8
|
|
|
9
|
-
import { getBlockInfoFromPos } from "../helpers/getBlockInfoFromPos";
|
|
10
|
-
import { PreviousBlockTypePlugin } from "../PreviousBlockTypePlugin";
|
|
11
|
-
import styles from "./Block.module.css";
|
|
12
|
-
import BlockAttributes from "./BlockAttributes";
|
|
13
9
|
import {
|
|
14
10
|
BlockNoteDOMAttributes,
|
|
15
11
|
BlockSchema,
|
|
16
12
|
PartialBlock,
|
|
17
13
|
} from "../api/blockTypes";
|
|
14
|
+
import { getBlockInfoFromPos } from "../helpers/getBlockInfoFromPos";
|
|
15
|
+
import { PreviousBlockTypePlugin } from "../PreviousBlockTypePlugin";
|
|
16
|
+
import styles from "./Block.module.css";
|
|
17
|
+
import BlockAttributes from "./BlockAttributes";
|
|
18
18
|
import { mergeCSSClasses } from "../../../shared/utils";
|
|
19
19
|
|
|
20
20
|
declare module "@tiptap/core" {
|
|
@@ -60,7 +60,7 @@ export const BlockContainer = Node.create<{
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
const attrs: Record<string, string> = {};
|
|
63
|
-
for (
|
|
63
|
+
for (const [nodeAttr, HTMLAttr] of Object.entries(BlockAttributes)) {
|
|
64
64
|
if (element.getAttribute(HTMLAttr)) {
|
|
65
65
|
attrs[nodeAttr] = element.getAttribute(HTMLAttr)!;
|
|
66
66
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Selection } from "prosemirror-state";
|
|
2
1
|
import { Fragment, Node, ResolvedPos, Slice } from "prosemirror-model";
|
|
2
|
+
import { Selection } from "prosemirror-state";
|
|
3
3
|
import { Mappable } from "prosemirror-transform";
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -64,8 +64,8 @@ export class MultipleNodeSelection extends Selection {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
map(doc: Node, mapping: Mappable): Selection {
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
const fromResult = mapping.mapResult(this.from);
|
|
68
|
+
const toResult = mapping.mapResult(this.to);
|
|
69
69
|
|
|
70
70
|
if (toResult.deleted) {
|
|
71
71
|
return Selection.near(doc.resolve(fromResult.pos));
|
|
@@ -32,7 +32,7 @@ function getDraggableBlockFromCoords(
|
|
|
32
32
|
return undefined;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
const pos = view.posAtCoords(coords);
|
|
36
36
|
if (!pos) {
|
|
37
37
|
return undefined;
|
|
38
38
|
}
|
|
@@ -61,12 +61,12 @@ function blockPositionFromCoords(
|
|
|
61
61
|
coords: { left: number; top: number },
|
|
62
62
|
view: EditorView
|
|
63
63
|
) {
|
|
64
|
-
|
|
64
|
+
const block = getDraggableBlockFromCoords(coords, view);
|
|
65
65
|
|
|
66
66
|
if (block && block.node.nodeType === 1) {
|
|
67
67
|
// TODO: this uses undocumented PM APIs? do we need this / let's add docs?
|
|
68
68
|
const docView = (view as any).docView;
|
|
69
|
-
|
|
69
|
+
const desc = docView.nearestDesc(block.node, true);
|
|
70
70
|
if (!desc || desc === docView) {
|
|
71
71
|
return null;
|
|
72
72
|
}
|
|
@@ -186,12 +186,12 @@ function dragStart(
|
|
|
186
186
|
|
|
187
187
|
const editorBoundingBox = view.dom.getBoundingClientRect();
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
const coords = {
|
|
190
190
|
left: editorBoundingBox.left + editorBoundingBox.width / 2, // take middle of editor
|
|
191
191
|
top: e.clientY,
|
|
192
192
|
};
|
|
193
193
|
|
|
194
|
-
|
|
194
|
+
const pos = blockPositionFromCoords(coords, view);
|
|
195
195
|
if (pos != null) {
|
|
196
196
|
const selection = view.state.selection;
|
|
197
197
|
const doc = view.state.doc;
|
|
@@ -215,8 +215,8 @@ function dragStart(
|
|
|
215
215
|
setDragImage(view, pos);
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
const slice = view.state.selection.content();
|
|
219
|
+
const { dom, text } = serializeForClipboard(view, slice);
|
|
220
220
|
|
|
221
221
|
e.dataTransfer.clearData();
|
|
222
222
|
e.dataTransfer.setData("text/html", dom.innerHTML);
|
|
@@ -288,7 +288,7 @@ export class SideMenuView<BSchema extends BlockSchema> implements PluginView {
|
|
|
288
288
|
return;
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
|
|
291
|
+
const pos = this.pmView.posAtCoords({
|
|
292
292
|
left: event.clientX,
|
|
293
293
|
top: event.clientY,
|
|
294
294
|
});
|
|
@@ -319,7 +319,7 @@ export class SideMenuView<BSchema extends BlockSchema> implements PluginView {
|
|
|
319
319
|
if ((event as any).synthetic || !this.isDragging) {
|
|
320
320
|
return;
|
|
321
321
|
}
|
|
322
|
-
|
|
322
|
+
const pos = this.pmView.posAtCoords({
|
|
323
323
|
left: event.clientX,
|
|
324
324
|
top: event.clientY,
|
|
325
325
|
});
|
|
@@ -52,14 +52,15 @@ const UniqueID = Extension.create({
|
|
|
52
52
|
types: [],
|
|
53
53
|
generateID: () => {
|
|
54
54
|
// Use mock ID if tests are running.
|
|
55
|
-
if ((window as any).__TEST_OPTIONS) {
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
if (typeof window !== "undefined" && (window as any).__TEST_OPTIONS) {
|
|
56
|
+
const testOptions = (window as any).__TEST_OPTIONS;
|
|
57
|
+
if (testOptions.mockID === undefined) {
|
|
58
|
+
testOptions.mockID = 0;
|
|
58
59
|
} else {
|
|
59
|
-
|
|
60
|
+
testOptions.mockID++;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
return
|
|
63
|
+
return testOptions.mockID.toString() as string;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
return v4();
|
|
@@ -129,7 +130,7 @@ const UniqueID = Extension.create({
|
|
|
129
130
|
const filterTransactions =
|
|
130
131
|
this.options.filterTransaction &&
|
|
131
132
|
transactions.some((tr) => {
|
|
132
|
-
|
|
133
|
+
let _a, _b;
|
|
133
134
|
return !((_b = (_a = this.options).filterTransaction) === null ||
|
|
134
135
|
_b === void 0
|
|
135
136
|
? void 0
|
|
@@ -161,7 +162,7 @@ const UniqueID = Extension.create({
|
|
|
161
162
|
.filter((id) => id !== null);
|
|
162
163
|
const duplicatedNewIds = findDuplicates(newIds);
|
|
163
164
|
newNodes.forEach(({ node, pos }) => {
|
|
164
|
-
|
|
165
|
+
let _a;
|
|
165
166
|
// instead of checking `node.attrs[attributeName]` directly
|
|
166
167
|
// we look at the current state of the node within `tr.doc`.
|
|
167
168
|
// this helps to prevent adding new ids to the same node
|
|
@@ -196,7 +197,7 @@ const UniqueID = Extension.create({
|
|
|
196
197
|
// we register a global drag handler to track the current drag source element
|
|
197
198
|
view(view) {
|
|
198
199
|
const handleDragstart = (event: any) => {
|
|
199
|
-
|
|
200
|
+
let _a;
|
|
200
201
|
dragSourceElement = (
|
|
201
202
|
(_a = view.dom.parentElement) === null || _a === void 0
|
|
202
203
|
? void 0
|
|
@@ -219,7 +220,7 @@ const UniqueID = Extension.create({
|
|
|
219
220
|
// only create new ids for dropped content while holding `alt`
|
|
220
221
|
// or content is dragged from another editor
|
|
221
222
|
drop: (view, event: any) => {
|
|
222
|
-
|
|
223
|
+
let _a;
|
|
223
224
|
if (
|
|
224
225
|
dragSourceElement !== view.dom.parentElement ||
|
|
225
226
|
((_a = event.dataTransfer) === null || _a === void 0
|
|
@@ -11,6 +11,7 @@ type CallbackFunction<
|
|
|
11
11
|
> = (...props: CallbackType<T, EventName>) => any;
|
|
12
12
|
|
|
13
13
|
export class EventEmitter<T extends Record<string, any>> {
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
14
15
|
private callbacks: { [key: string]: Function[] } = {};
|
|
15
16
|
|
|
16
17
|
public on<EventName extends StringKeyOf<T>>(
|
|
@@ -28,7 +28,9 @@ class SuggestionsMenuView<
|
|
|
28
28
|
private readonly pluginKey: PluginKey,
|
|
29
29
|
updateSuggestionsMenu: (
|
|
30
30
|
suggestionsMenuState: SuggestionsMenuState<T>
|
|
31
|
-
) => void = () => {
|
|
31
|
+
) => void = () => {
|
|
32
|
+
// noop
|
|
33
|
+
}
|
|
32
34
|
) {
|
|
33
35
|
this.pluginState = getDefaultPluginState<T>();
|
|
34
36
|
|
|
@@ -158,7 +160,9 @@ export const setupSuggestionsMenu = <
|
|
|
158
160
|
onSelectItem: (props: {
|
|
159
161
|
item: T;
|
|
160
162
|
editor: BlockNoteEditor<BSchema>;
|
|
161
|
-
}) => void = () => {
|
|
163
|
+
}) => void = () => {
|
|
164
|
+
// noop
|
|
165
|
+
}
|
|
162
166
|
) => {
|
|
163
167
|
// Assertions
|
|
164
168
|
if (defaultTriggerCharacter.length !== 1) {
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { Node, NodeType } from "prosemirror-model";
|
|
2
|
-
export type
|
|
2
|
+
export type BlockInfoWithoutPositions = {
|
|
3
3
|
id: string;
|
|
4
4
|
node: Node;
|
|
5
5
|
contentNode: Node;
|
|
6
6
|
contentType: NodeType;
|
|
7
7
|
numChildBlocks: number;
|
|
8
|
+
};
|
|
9
|
+
export type BlockInfo = BlockInfoWithoutPositions & {
|
|
8
10
|
startPos: number;
|
|
9
11
|
endPos: number;
|
|
10
12
|
depth: number;
|
|
11
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Helper function for `getBlockInfoFromPos`, returns information regarding
|
|
16
|
+
* provided blockContainer node.
|
|
17
|
+
* @param blockContainer The blockContainer node to retrieve info for.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getBlockInfo(blockContainer: Node): BlockInfoWithoutPositions;
|
|
12
20
|
/**
|
|
13
21
|
* Retrieves information regarding the nearest blockContainer node in a
|
|
14
22
|
* ProseMirror doc, relative to a position.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Selection } from "prosemirror-state";
|
|
2
1
|
import { Node, ResolvedPos, Slice } from "prosemirror-model";
|
|
2
|
+
import { Selection } from "prosemirror-state";
|
|
3
3
|
import { Mappable } from "prosemirror-transform";
|
|
4
4
|
/**
|
|
5
5
|
* This class represents an editor selection which spans multiple nodes/blocks. It's currently only used to allow users
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
type StringKeyOf<T> = Extract<keyof T, string>;
|
|
2
|
-
type CallbackType<T extends Record<string, any>, EventName extends StringKeyOf<T>> = T[EventName] extends any[] ? T[EventName] : [T[EventName]];
|
|
3
|
-
type CallbackFunction<T extends Record<string, any>, EventName extends StringKeyOf<T>> = (...props: CallbackType<T, EventName>) => any;
|
|
4
|
-
export declare class EventEmitter<T extends Record<string, any>> {
|
|
5
|
-
private callbacks;
|
|
6
|
-
on<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>): this;
|
|
7
|
-
protected emit<EventName extends StringKeyOf<T>>(event: EventName, ...args: CallbackType<T, EventName>): this;
|
|
8
|
-
off<EventName extends StringKeyOf<T>>(event: EventName, fn?: CallbackFunction<T, EventName>): this;
|
|
9
|
-
protected removeAllListeners(): void;
|
|
10
|
-
}
|
|
11
|
-
export {};
|
|
File without changes
|