enh: task list rich text input

This commit is contained in:
Timothy Jaeryang Baek 2025-07-08 23:57:34 +04:00
parent f69db54b7e
commit 248fd10406
4 changed files with 85 additions and 0 deletions

29
package-lock.json generated
View file

@ -26,6 +26,8 @@
"@tiptap/extension-table-cell": "^2.12.0",
"@tiptap/extension-table-header": "^2.12.0",
"@tiptap/extension-table-row": "^2.12.0",
"@tiptap/extension-task-item": "^2.25.0",
"@tiptap/extension-task-list": "^2.25.0",
"@tiptap/extension-typography": "^2.10.0",
"@tiptap/pm": "^2.11.7",
"@tiptap/starter-kit": "^2.10.0",
@ -3247,6 +3249,33 @@
"@tiptap/core": "^2.7.0"
}
},
"node_modules/@tiptap/extension-task-item": {
"version": "2.25.0",
"resolved": "https://registry.npmjs.org/@tiptap/extension-task-item/-/extension-task-item-2.25.0.tgz",
"integrity": "sha512-8F7Z7jbsyGrPLHQCn+n39zdqIgxwR1kJ1nL5ZwhEW3ZhJgkFF0WMJSv36mwIJwL08p8um/c6g72AYB/e8CD7eA==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
"@tiptap/core": "^2.7.0",
"@tiptap/pm": "^2.7.0"
}
},
"node_modules/@tiptap/extension-task-list": {
"version": "2.25.0",
"resolved": "https://registry.npmjs.org/@tiptap/extension-task-list/-/extension-task-list-2.25.0.tgz",
"integrity": "sha512-2mASqp8MJ0dyc1OK6c8P7m/zwoVDv8PV+XsRR9O3tpIz/zjUVrOl0W4IndjUPBMa7cpJX8fGj8iC3DaRNpSMcg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
"@tiptap/core": "^2.7.0"
}
},
"node_modules/@tiptap/extension-text": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.10.0.tgz",

View file

@ -70,6 +70,8 @@
"@tiptap/extension-table-cell": "^2.12.0",
"@tiptap/extension-table-header": "^2.12.0",
"@tiptap/extension-table-row": "^2.12.0",
"@tiptap/extension-task-item": "^2.25.0",
"@tiptap/extension-task-list": "^2.25.0",
"@tiptap/extension-typography": "^2.10.0",
"@tiptap/pm": "^2.11.7",
"@tiptap/starter-kit": "^2.10.0",

View file

@ -330,6 +330,39 @@ input[type='number'] {
@apply line-clamp-1 absolute;
}
.tiptap ul[data-type='taskList'] {
list-style: none;
margin-left: 0;
padding: 0;
li {
align-items: center;
display: flex;
> label {
flex: 0 0 auto;
margin-right: 0.5rem;
user-select: none;
display: flex;
}
> div {
flex: 1 1 auto;
align-items: center;
}
}
input[type='checkbox'] {
cursor: pointer;
}
ul[data-type='taskList'] {
margin: 0;
}
}
@media (prefers-color-scheme: dark) {
.ProseMirror p.is-editor-empty:first-child::before {
color: #757575;

View file

@ -11,6 +11,18 @@
// Use turndown-plugin-gfm for proper GFM table support
turndownService.use(gfm);
turndownService.addRule('taskListItems', {
filter: (node) =>
node.nodeName === 'LI' &&
(node.getAttribute('data-checked') === 'true' ||
node.getAttribute('data-checked') === 'false'),
replacement: function (content, node) {
const checked = node.getAttribute('data-checked') === 'true';
content = content.replace(/^\s+/, '');
return `- [${checked ? 'x' : ' '}] ${content}\n`;
}
});
import { onMount, onDestroy, tick } from 'svelte';
import { createEventDispatcher } from 'svelte';
@ -27,6 +39,9 @@
import TableHeader from '@tiptap/extension-table-header';
import TableCell from '@tiptap/extension-table-cell';
import TaskItem from '@tiptap/extension-task-item';
import TaskList from '@tiptap/extension-task-list';
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight';
import Placeholder from '@tiptap/extension-placeholder';
import StarterKit from '@tiptap/starter-kit';
@ -437,6 +452,10 @@
TableRow,
TableHeader,
TableCell,
TaskList,
TaskItem.configure({
nested: true
}),
...(autocomplete
? [
AIAutocompletion.configure({
@ -464,6 +483,8 @@
const htmlValue = editor.getHTML();
const jsonValue = editor.getJSON();
console.log(htmlValue, jsonValue);
let mdValue = turndownService
.turndown(
htmlValue