Skip to content

Commit 06217a3

Browse files
m-ristoYousefED
andauthored
feat: add option to set html id (#1078)
* feat: add option to set html id * add unit test and rename option * undo example change --------- Co-authored-by: yousefed <yousefdardiry@gmail.com>
1 parent 9a741d7 commit 06217a3

File tree

5 files changed

+44
-7
lines changed

5 files changed

+44
-7
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import "@blocknote/core/fonts/inter.css";
2-
import { useCreateBlockNote } from "@blocknote/react";
32
import { BlockNoteView } from "@blocknote/mantine";
43
import "@blocknote/mantine/style.css";
4+
import { useCreateBlockNote } from "@blocknote/react";
55

66
export default function App() {
77
// Creates a new editor instance.

packages/core/src/editor/BlockNoteEditor.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,16 @@ it("immediately replaces doc", async () => {
5757
]
5858
`);
5959
});
60+
61+
it("adds id attribute when requested", async () => {
62+
const editor = BlockNoteEditor.create({
63+
setIdAttribute: true,
64+
});
65+
const blocks = await editor.tryParseMarkdownToBlocks(
66+
"This is a normal text\n\n# And this is a large heading"
67+
);
68+
editor.replaceBlocks(editor.document, blocks);
69+
expect(
70+
await editor.blocksToFullHTML(editor.document)
71+
).toMatchInlineSnapshot(`"<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1" id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1" id="1"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">This is a normal text</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="2" id="2"><div class="bn-block" data-node-type="blockContainer" data-id="2" id="2"><div class="bn-block-content" data-content-type="heading" data-level="1"><h1 class="bn-inline-content">And this is a large heading</h1></div></div></div></div>"`);
72+
});

packages/core/src/editor/BlockNoteEditor.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ export type BlockNoteEditorOptions<
166166
* You probably don't need to set this manually, but use the `server-util` package instead that uses this option internally
167167
*/
168168
_headless: boolean;
169+
170+
/**
171+
* A flag indicating whether to set an HTML ID for every block
172+
*
173+
* When set to `true`, on each block an id attribute will be set with the block id
174+
* Otherwise, the HTML ID attribute will not be set.
175+
*
176+
* (note that the id is always set on the `data-id` attribute)
177+
*/
178+
setIdAttribute?: boolean;
169179
};
170180

171181
const blockNoteTipTapOptions = {
@@ -339,6 +349,7 @@ export class BlockNoteEditor<
339349
collaboration: newOptions.collaboration,
340350
trailingBlock: newOptions.trailingBlock,
341351
disableExtensions: newOptions.disableExtensions,
352+
setIdAttribute: newOptions.setIdAttribute,
342353
});
343354

344355
const blockNoteUIExtension = Extension.create({

packages/core/src/editor/BlockNoteExtensions.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { Link } from "@tiptap/extension-link";
1212
import { Text } from "@tiptap/extension-text";
1313
import * as Y from "yjs";
1414
import { createCopyToClipboardExtension } from "../api/exporters/copyExtension";
15-
import { createPasteFromClipboardExtension } from "../api/parsers/pasteExtension";
1615
import { createDropFileExtension } from "../api/parsers/fileDropExtension";
16+
import { createPasteFromClipboardExtension } from "../api/parsers/pasteExtension";
1717
import { BackgroundColorExtension } from "../extensions/BackgroundColor/BackgroundColorExtension";
1818
import { TextAlignmentExtension } from "../extensions/TextAlignment/TextAlignmentExtension";
1919
import { TextColorExtension } from "../extensions/TextColor/TextColorExtension";
@@ -55,6 +55,7 @@ export const getBlockNoteExtensions = <
5555
renderCursor?: (user: any) => HTMLElement;
5656
};
5757
disableExtensions: string[] | undefined;
58+
setIdAttribute?: boolean;
5859
}) => {
5960
const ret: Extensions = [
6061
extensions.ClipboardTextSerializer,
@@ -69,6 +70,7 @@ export const getBlockNoteExtensions = <
6970
// DropCursor,
7071
UniqueID.configure({
7172
types: ["blockContainer"],
73+
setIdAttribute: opts.setIdAttribute,
7274
}),
7375
HardBreak.extend({ priority: 10 }),
7476
// Comments,
@@ -197,5 +199,5 @@ export const getBlockNoteExtensions = <
197199
}
198200

199201
const disableExtensions: string[] = opts.disableExtensions || [];
200-
return ret.filter(ex => !disableExtensions.includes(ex.name));
202+
return ret.filter((ex) => !disableExtensions.includes(ex.name));
201203
};

packages/core/src/extensions/UniqueID/UniqueID.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const UniqueID = Extension.create({
5050
return {
5151
attributeName: "id",
5252
types: [],
53+
setIdAttribute: false,
5354
generateID: () => {
5455
// Use mock ID if tests are running.
5556
if (typeof window !== "undefined" && (window as any).__TEST_OPTIONS) {
@@ -77,10 +78,20 @@ const UniqueID = Extension.create({
7778
default: null,
7879
parseHTML: (element) =>
7980
element.getAttribute(`data-${this.options.attributeName}`),
80-
renderHTML: (attributes) => ({
81-
[`data-${this.options.attributeName}`]:
82-
attributes[this.options.attributeName],
83-
}),
81+
renderHTML: (attributes) => {
82+
const defaultIdAttributes = {
83+
[`data-${this.options.attributeName}`]:
84+
attributes[this.options.attributeName],
85+
};
86+
if (this.options.setIdAttribute) {
87+
return {
88+
...defaultIdAttributes,
89+
id: attributes[this.options.attributeName],
90+
};
91+
} else {
92+
return defaultIdAttributes;
93+
}
94+
},
8495
},
8596
},
8697
},

0 commit comments

Comments
 (0)