Skip to content

Commit 02b1f17

Browse files
committed
try suggestion-node prefix approach
1 parent be86b22 commit 02b1f17

9 files changed

Lines changed: 1035 additions & 316 deletions

File tree

examples/01-basic/01-minimal/src/App.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,23 @@ export default function App() {
99
const editor = useCreateBlockNote();
1010

1111
// After the editor is created, replace its document with a ProseMirror
12-
// structure that includes a specialNode before the blockContainer's paragraph.
12+
// structure that includes a suggestion-paragraph before the blockContainer's paragraph.
1313
useEffect(() => {
1414
// Use editor.transact to dispatch a ProseMirror transaction that replaces
1515
// the entire document content.
1616
editor.transact((tr) => {
1717
const { nodes } = editor.pmSchema;
1818

19-
// Build the specialNode containing a paragraph
20-
const specialParagraph = nodes.paragraph.create(
19+
// Build the suggestion-paragraph (shadow node for suggestions)
20+
const suggestionParagraph = nodes["suggestion-paragraph"].create(
2121
{
2222
backgroundColor: "default",
2323
textAlignment: "left",
2424
textColor: "default",
25+
__suggestionData: "true",
2526
},
26-
[editor.pmSchema.text("Hello from specialNode!")],
27+
[editor.pmSchema.text("Hello from suggestion-paragraph!")],
2728
);
28-
const specialNode = nodes.specialNode.create(null, [specialParagraph]);
2929

3030
// Build the main blockContent paragraph
3131
const mainParagraph = nodes.paragraph.create(
@@ -37,18 +37,17 @@ export default function App() {
3737
[editor.pmSchema.text("Hello from blockContainer!")],
3838
);
3939

40-
// Build the blockContainer with specialNode before blockContent
40+
// Build the blockContainer with suggestion-paragraph before blockContent
4141
//
4242
// Target structure:
4343
// doc
4444
// └─ blockGroup
4545
// └─ blockContainer
46-
// ├─ specialNode
47-
// │ └─ paragraph("Hello from specialNode!")
46+
// ├─ suggestion-paragraph("Hello from suggestion-paragraph!")
4847
// └─ paragraph("Hello from blockContainer!")
4948
const blockContainer = nodes.blockContainer.create(
5049
{ id: "block-1" },
51-
[specialNode, mainParagraph],
50+
[suggestionParagraph, mainParagraph],
5251
);
5352

5453
const blockGroup = nodes.blockGroup.create(null, [blockContainer]);

packages/core/src/editor/managers/ExtensionManager/extensions.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import {
4242
BlockContainer,
4343
BlockGroup,
4444
Doc,
45-
SpecialNode,
4645
} from "../../../pm-nodes/index.js";
4746
import type {
4847
BlockNoteEditor,
@@ -119,10 +118,6 @@ export function getDefaultTiptapExtensions(
119118
BlockGroup.configure({
120119
domAttributes: options.domAttributes,
121120
}),
122-
SpecialNode.configure({
123-
editor: editor,
124-
domAttributes: options.domAttributes,
125-
}),
126121
...Object.values(editor.schema.inlineContentSpecs)
127122
.filter((a) => a.config !== "link" && a.config !== "text")
128123
.map((inlineContentSpec) => {
@@ -142,6 +137,16 @@ export function getDefaultTiptapExtensions(
142137
}),
143138
]
144139
: []),
140+
// suggestion shadow node (same block, no parseHTML, different group)
141+
...("suggestionNode" in blockSpec.implementation &&
142+
blockSpec.implementation.suggestionNode
143+
? [
144+
(blockSpec.implementation.suggestionNode as Node).configure({
145+
editor: editor,
146+
domAttributes: options.domAttributes,
147+
}),
148+
]
149+
: []),
145150
];
146151
}),
147152
createCopyToClipboardExtension(editor),

packages/core/src/pm-nodes/BlockContainer.ts

Lines changed: 1 addition & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -13,88 +13,6 @@ const BlockAttributes: Record<string, string> = {
1313
depthChange: "data-depth-change",
1414
};
1515

16-
/**
17-
* The main "Block node" documents consist of
18-
*/
19-
export const SpecialNode = Node.create<{
20-
domAttributes?: BlockNoteDOMAttributes;
21-
editor: BlockNoteEditor<any, any, any>;
22-
}>({
23-
name: "specialNode",
24-
group: "blockGroupChild bnBlock bnSpecialNode",
25-
// A block always contains content, and optionally a blockGroup which contains nested blocks
26-
content: "blockContent blockGroup?",
27-
// Ensures content-specific keyboard handlers trigger first.
28-
priority: 50,
29-
defining: true,
30-
marks: "y-attributed-insert y-attributed-format y-attributed-delete",
31-
addAttributes() {
32-
return {
33-
XYZ: {
34-
isRequired: true,
35-
type: "string",
36-
},
37-
};
38-
},
39-
parseHTML() {
40-
return [
41-
// TODO not sure whether this rule is needed or not
42-
// {
43-
// tag: "div[data-node-type=" + this.name + "]",
44-
// getAttrs: (element) => {
45-
// if (typeof element === "string") {
46-
// return false;
47-
// }
48-
49-
// const attrs: Record<string, string> = {};
50-
// for (const [nodeAttr, HTMLAttr] of Object.entries(BlockAttributes)) {
51-
// if (element.getAttribute(HTMLAttr)) {
52-
// attrs[nodeAttr] = element.getAttribute(HTMLAttr)!;
53-
// }
54-
// }
55-
56-
// return attrs;
57-
// },
58-
// },
59-
// Ignore `blockOuter` divs, but parse the `blockContainer` divs inside them.
60-
{
61-
tag: `div[data-node-type="specialNodeOuter"]`,
62-
skip: true,
63-
},
64-
];
65-
},
66-
67-
renderHTML({ HTMLAttributes }) {
68-
const specialNodeOuter = document.createElement("div");
69-
specialNodeOuter.className = "bn-block-outer";
70-
specialNodeOuter.setAttribute("data-node-type", "specialNodeOuter");
71-
for (const [attribute, value] of Object.entries(HTMLAttributes)) {
72-
if (attribute !== "class") {
73-
specialNodeOuter.setAttribute(attribute, value);
74-
}
75-
}
76-
77-
const blockHTMLAttributes = {
78-
...(this.options.domAttributes?.block || {}),
79-
...HTMLAttributes,
80-
};
81-
const block = document.createElement("div");
82-
block.className = mergeCSSClasses("bn-block", blockHTMLAttributes.class);
83-
block.setAttribute("data-node-type", this.name);
84-
for (const [attribute, value] of Object.entries(blockHTMLAttributes)) {
85-
if (attribute !== "class") {
86-
block.setAttribute(attribute, value);
87-
}
88-
}
89-
90-
specialNodeOuter.appendChild(block);
91-
92-
return {
93-
dom: specialNodeOuter,
94-
contentDOM: block,
95-
};
96-
},
97-
});
9816
/**
9917
* The main "Block node" documents consist of
10018
*/
@@ -105,7 +23,7 @@ export const BlockContainer = Node.create<{
10523
name: "blockContainer",
10624
group: "blockGroupChild bnBlock",
10725
// A block always contains content, and optionally a blockGroup which contains nested blocks
108-
content: "bnSpecialNode? blockContent bnSpecialNode? blockGroup?",
26+
content: "suggestionBlockContent? blockContent suggestionBlockContent? blockGroup?",
10927
// Ensures content-specific keyboard handlers trigger first.
11028
priority: 50,
11129
defining: true,

0 commit comments

Comments
 (0)