Skip to content

Commit e4234b0

Browse files
feat: Checkbox/TODO list item block (#729)
* v0.12.0 * v0.12.1 * v0.12.2 * v0.12.3 * v0.12.4 * v0.13.0 * v0.13.1 * Added check list default block * Implemented PR feedback * Updated screenshots * Fixed check list item HTML/Markdown conversion * Updated locales * Updated screenshots * Updated check list external HTML * Updated check list parse HTML * Made check list item not editable when the editor isn't * Fixes to check list item parsing, rendering, and exporting * Implemented PR feedback * Small fix --------- Co-authored-by: yousefed <[email protected]>
1 parent 0fff823 commit e4234b0

File tree

48 files changed

+1289
-132
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1289
-132
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<ul><li><p class="bn-inline-content">Bullet List Item 1</p></li><li><p class="bn-inline-content">Bullet List Item 2</p></li></ul><ol><li><p class="bn-inline-content">Numbered List Item 1</p></li><li><p class="bn-inline-content">Numbered List Item 2</p></li></ol><ul><li><input type="checkbox"><p class="bn-inline-content">Check List Item 1</p></li><li><input type="checkbox" checked><p class="bn-inline-content">Check List Item 2</p></li></ul>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1"><div class="bn-block-content" data-content-type="bulletListItem"><p class="bn-inline-content">Bullet List Item 1</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="2"><div class="bn-block" data-node-type="blockContainer" data-id="2"><div class="bn-block-content" data-content-type="bulletListItem"><p class="bn-inline-content">Bullet List Item 2</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="3"><div class="bn-block" data-node-type="blockContainer" data-id="3"><div class="bn-block-content" data-content-type="numberedListItem" data-index="null"><p class="bn-inline-content">Numbered List Item 1</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="4"><div class="bn-block" data-node-type="blockContainer" data-id="4"><div class="bn-block-content" data-content-type="numberedListItem" data-index="null"><p class="bn-inline-content">Numbered List Item 2</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="5"><div class="bn-block" data-node-type="blockContainer" data-id="5"><div class="bn-block-content" data-content-type="checkListItem"><input type="checkbox"><p class="bn-inline-content">Check List Item 1</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="6"><div class="bn-block" data-node-type="blockContainer" data-id="6"><div class="bn-block-content" data-content-type="checkListItem" data-checked="true"><input type="checkbox" checked=""><p class="bn-inline-content">Check List Item 2</p></div></div></div></div>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<ul><li><p class="bn-inline-content">Bullet List Item 1</p></li><li><p class="bn-inline-content">Bullet List Item 2</p><ol><li><p class="bn-inline-content">Numbered List Item 1</p></li><li><p class="bn-inline-content">Numbered List Item 2</p><ul><li><input type="checkbox"><p class="bn-inline-content">Check List Item 1</p></li><li><input type="checkbox" checked><p class="bn-inline-content">Check List Item 2</p></li></ul></li></ol></li></ul>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1"><div class="bn-block-content" data-content-type="bulletListItem"><p class="bn-inline-content">Bullet List Item 1</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="2"><div class="bn-block" data-node-type="blockContainer" data-id="2"><div class="bn-block-content" data-content-type="bulletListItem"><p class="bn-inline-content">Bullet List Item 2</p></div><div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="3"><div class="bn-block" data-node-type="blockContainer" data-id="3"><div class="bn-block-content" data-content-type="numberedListItem" data-index="null"><p class="bn-inline-content">Numbered List Item 1</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="4"><div class="bn-block" data-node-type="blockContainer" data-id="4"><div class="bn-block-content" data-content-type="numberedListItem" data-index="null"><p class="bn-inline-content">Numbered List Item 2</p></div><div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="5"><div class="bn-block" data-node-type="blockContainer" data-id="5"><div class="bn-block-content" data-content-type="checkListItem"><input type="checkbox"><p class="bn-inline-content">Check List Item 1</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="6"><div class="bn-block" data-node-type="blockContainer" data-id="6"><div class="bn-block-content" data-content-type="checkListItem" data-checked="true"><input type="checkbox" checked=""><p class="bn-inline-content">Check List Item 2</p></div></div></div></div></div></div></div></div></div></div>

packages/core/src/api/exporters/html/externalHTMLExporter.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ export const createExternalHTMLExporter = <
7373
.use(rehypeParse, { fragment: true })
7474
.use(simplifyBlocks, {
7575
orderedListItemBlockTypes: new Set<string>(["numberedListItem"]),
76-
unorderedListItemBlockTypes: new Set<string>(["bulletListItem"]),
76+
unorderedListItemBlockTypes: new Set<string>([
77+
"bulletListItem",
78+
"checkListItem",
79+
]),
7780
})
7881
.use(rehypeStringify)
7982
.processSync(serializeProseMirrorFragment(fragment, serializer));

packages/core/src/api/exporters/html/util/simplifyBlocksRehypePlugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export function simplifyBlocks(options: SimplifyBlocksOptions) {
9898
) as HASTElement;
9999

100100
// Adds only the content inside the block to the active list.
101-
listItemElement.children.push(blockContent.children[0]);
101+
listItemElement.children.push(...blockContent.children);
102102
// Nested blocks have already been processed in the recursive function call, so the resulting elements are
103103
// also added to the active list.
104104
if (blockGroup !== null) {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
* Bullet List Item 1
2+
* Bullet List Item 2
3+
4+
1. Numbered List Item 1
5+
2. Numbered List Item 2
6+
7+
* \[ ] Check List Item 1
8+
* \[x] Check List Item 2
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
* Bullet List Item 1
2+
3+
* Bullet List Item 2
4+
5+
1. Numbered List Item 1
6+
7+
2. Numbered List Item 2
8+
9+
* \[ ] Check List Item 1
10+
* \[x] Check List Item 2

packages/core/src/api/exporters/markdown/markdownExporter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import type { BlockNoteEditor } from "../../../editor/BlockNoteEditor";
99
import { BlockSchema, InlineContentSchema, StyleSchema } from "../../../schema";
1010
import { createExternalHTMLExporter } from "../html/externalHTMLExporter";
1111
import { removeUnderlines } from "./removeUnderlinesRehypePlugin";
12+
import { addSpacesToCheckboxes } from "./util/addSpacesToCheckboxesRehypePlugin";
1213

1314
export function cleanHTMLToMarkdown(cleanHTMLString: string) {
1415
const markdownString = unified()
1516
.use(rehypeParse, { fragment: true })
1617
.use(removeUnderlines)
18+
.use(addSpacesToCheckboxes)
1719
.use(rehypeRemark)
1820
.use(remarkGfm)
1921
.use(remarkStringify)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Element as HASTElement, Parent as HASTParent } from "hast";
2+
import { fromDom } from "hast-util-from-dom";
3+
4+
/**
5+
* Rehype plugin which adds a space after each checkbox input element. This is
6+
* because remark doesn't add any spaces between the checkbox input and the text
7+
* itself, but these are needed for correct Markdown syntax.
8+
*/
9+
export function addSpacesToCheckboxes() {
10+
const helper = (tree: HASTParent) => {
11+
if (tree.children && "length" in tree.children && tree.children.length) {
12+
for (let i = tree.children.length - 1; i >= 0; i--) {
13+
const child = tree.children[i];
14+
const nextChild =
15+
i + 1 < tree.children.length ? tree.children[i + 1] : undefined;
16+
17+
// Checks for paragraph element after checkbox input element.
18+
if (
19+
child.type === "element" &&
20+
child.tagName === "input" &&
21+
child.properties?.type === "checkbox" &&
22+
nextChild?.type === "element" &&
23+
nextChild.tagName === "p"
24+
) {
25+
// Converts paragraph to span, otherwise remark will think it needs to
26+
// be on a new line.
27+
nextChild.tagName = "span";
28+
// Adds a space after the checkbox input element.
29+
nextChild.children.splice(
30+
0,
31+
0,
32+
fromDom(document.createTextNode(" ")) as HASTElement
33+
);
34+
} else {
35+
helper(child as HASTParent);
36+
}
37+
}
38+
}
39+
};
40+
41+
return helper;
42+
}

0 commit comments

Comments
 (0)