Skip to content

Commit

Permalink
feat: Checkbox/TODO list item block (#729)
Browse files Browse the repository at this point in the history
* 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 <yousefdardiry@gmail.com>
  • Loading branch information
matthewlipski and YousefED committed May 24, 2024
1 parent 0fff823 commit e4234b0
Show file tree
Hide file tree
Showing 48 changed files with 1,289 additions and 132 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +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>
Original file line number Diff line number Diff line change
@@ -0,0 +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>
Original file line number Diff line number Diff line change
@@ -0,0 +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>
Original file line number Diff line number Diff line change
@@ -0,0 +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>
5 changes: 4 additions & 1 deletion packages/core/src/api/exporters/html/externalHTMLExporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ export const createExternalHTMLExporter = <
.use(rehypeParse, { fragment: true })
.use(simplifyBlocks, {
orderedListItemBlockTypes: new Set<string>(["numberedListItem"]),
unorderedListItemBlockTypes: new Set<string>(["bulletListItem"]),
unorderedListItemBlockTypes: new Set<string>([
"bulletListItem",
"checkListItem",
]),
})
.use(rehypeStringify)
.processSync(serializeProseMirrorFragment(fragment, serializer));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export function simplifyBlocks(options: SimplifyBlocksOptions) {
) as HASTElement;

// Adds only the content inside the block to the active list.
listItemElement.children.push(blockContent.children[0]);
listItemElement.children.push(...blockContent.children);
// Nested blocks have already been processed in the recursive function call, so the resulting elements are
// also added to the active list.
if (blockGroup !== null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
* Bullet List Item 1
* Bullet List Item 2

1. Numbered List Item 1
2. Numbered List Item 2

* \[ ] Check List Item 1
* \[x] Check List Item 2
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
* Bullet List Item 1

* Bullet List Item 2

1. Numbered List Item 1

2. Numbered List Item 2

* \[ ] Check List Item 1
* \[x] Check List Item 2
2 changes: 2 additions & 0 deletions packages/core/src/api/exporters/markdown/markdownExporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import type { BlockNoteEditor } from "../../../editor/BlockNoteEditor";
import { BlockSchema, InlineContentSchema, StyleSchema } from "../../../schema";
import { createExternalHTMLExporter } from "../html/externalHTMLExporter";
import { removeUnderlines } from "./removeUnderlinesRehypePlugin";
import { addSpacesToCheckboxes } from "./util/addSpacesToCheckboxesRehypePlugin";

export function cleanHTMLToMarkdown(cleanHTMLString: string) {
const markdownString = unified()
.use(rehypeParse, { fragment: true })
.use(removeUnderlines)
.use(addSpacesToCheckboxes)
.use(rehypeRemark)
.use(remarkGfm)
.use(remarkStringify)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Element as HASTElement, Parent as HASTParent } from "hast";
import { fromDom } from "hast-util-from-dom";

/**
* Rehype plugin which adds a space after each checkbox input element. This is
* because remark doesn't add any spaces between the checkbox input and the text
* itself, but these are needed for correct Markdown syntax.
*/
export function addSpacesToCheckboxes() {
const helper = (tree: HASTParent) => {
if (tree.children && "length" in tree.children && tree.children.length) {
for (let i = tree.children.length - 1; i >= 0; i--) {
const child = tree.children[i];
const nextChild =
i + 1 < tree.children.length ? tree.children[i + 1] : undefined;

// Checks for paragraph element after checkbox input element.
if (
child.type === "element" &&
child.tagName === "input" &&
child.properties?.type === "checkbox" &&
nextChild?.type === "element" &&
nextChild.tagName === "p"
) {
// Converts paragraph to span, otherwise remark will think it needs to
// be on a new line.
nextChild.tagName = "span";
// Adds a space after the checkbox input element.
nextChild.children.splice(
0,
0,
fromDom(document.createTextNode(" ")) as HASTElement
);
} else {
helper(child as HASTParent);
}
}
}
};

return helper;
}
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,56 @@ exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert
}
`;

exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert lists/basic to/from prosemirror 1`] = `
{
"attrs": {
"backgroundColor": "default",
"id": "1",
"textColor": "default",
},
"content": [
{
"attrs": {
"textAlignment": "left",
},
"content": [
{
"text": "Bullet List Item 1",
"type": "text",
},
],
"type": "bulletListItem",
},
],
"type": "blockContainer",
}
`;

exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert lists/nested to/from prosemirror 1`] = `
{
"attrs": {
"backgroundColor": "default",
"id": "1",
"textColor": "default",
},
"content": [
{
"attrs": {
"textAlignment": "left",
},
"content": [
{
"text": "Bullet List Item 1",
"type": "text",
},
],
"type": "bulletListItem",
},
],
"type": "blockContainer",
}
`;

exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert paragraph/basic to/from prosemirror 1`] = `
{
"attrs": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,42 @@
},
{
"id": "4",
"type": "checkListItem",
"props": {
"textColor": "default",
"backgroundColor": "default",
"textAlignment": "left",
"checked": false
},
"content": [
{
"type": "text",
"text": "Fourth",
"styles": {}
}
],
"children": []
},
{
"id": "5",
"type": "checkListItem",
"props": {
"textColor": "default",
"backgroundColor": "default",
"textAlignment": "left",
"checked": false
},
"content": [
{
"type": "text",
"text": "Fifth",
"styles": {}
}
],
"children": []
},
{
"id": "6",
"type": "bulletListItem",
"props": {
"textColor": "default",
Expand All @@ -67,7 +103,7 @@
],
"children": [
{
"id": "5",
"id": "7",
"type": "bulletListItem",
"props": {
"textColor": "default",
Expand All @@ -84,7 +120,7 @@
"children": []
},
{
"id": "6",
"id": "8",
"type": "bulletListItem",
"props": {
"textColor": "default",
Expand All @@ -99,6 +135,42 @@
}
],
"children": []
},
{
"id": "9",
"type": "checkListItem",
"props": {
"textColor": "default",
"backgroundColor": "default",
"textAlignment": "left",
"checked": false
},
"content": [
{
"type": "text",
"text": "Child 3",
"styles": {}
}
],
"children": []
},
{
"id": "10",
"type": "checkListItem",
"props": {
"textColor": "default",
"backgroundColor": "default",
"textAlignment": "left",
"checked": false
},
"content": [
{
"type": "text",
"text": "Child 4",
"styles": {}
}
],
"children": []
}
]
}
Expand Down
Loading

0 comments on commit e4234b0

Please sign in to comment.