Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cypress/e2e/nodes/ListItem.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ListItem, OrderedList } from '@tiptap/extension-list'
/* eslint-enable import/no-named-as-default */
import Markdown from './../../../src/extensions/Markdown.js'
import BulletList from './../../../src/nodes/BulletList.ts'
import TaskItem from './../../../src/nodes/TaskItem.js'
import TaskItem from './../../../src/nodes/TaskItem.ts'
import TaskList from './../../../src/nodes/TaskList.ts'
import { createCustomEditor } from './../../support/components.js'
import { expectMarkdown, loadMarkdown, runCommands } from './helpers.js'
Expand Down
4 changes: 2 additions & 2 deletions src/css/prosemirror.scss
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ div.ProseMirror {
background-color: var(--color-primary-element);
border-color: var(--color-primary-element);
}
> label > p {
> .task-item-content > p {
color: var(--color-text-maxcontrast);
}
}
label {
.task-item-content {
display: block;
flex-grow: 1;
max-width: calc(100% - 28px);
Expand Down
2 changes: 1 addition & 1 deletion src/extensions/RichText.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import OrderedList from './../nodes/OrderedList.ts'
import Paragraph from './../nodes/Paragraph.js'
import Preview from './../nodes/Preview.js'
import Table from './../nodes/Table.js'
import TaskItem from './../nodes/TaskItem.js'
import TaskItem from './../nodes/TaskItem.ts'
import TaskList from './../nodes/TaskList.ts'
import TrailingNode from './../nodes/TrailingNode.js'
import Emoji from './Emoji.js'
Expand Down
60 changes: 36 additions & 24 deletions src/nodes/TaskItem.js → src/nodes/TaskItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { Node } from '@tiptap/pm/model'
import type { MarkdownSerializerState } from 'prosemirror-markdown'

import { mergeAttributes, wrappingInputRule } from '@tiptap/core'
import { TaskItem as TipTapTaskItem } from '@tiptap/extension-list'
import { Plugin } from '@tiptap/pm/state'
Expand All @@ -13,6 +16,7 @@ const TaskItem = TipTapTaskItem.extend({
return {
nested: true,
HTMLAttributes: {},
taskListTypeName: 'taskList',
}
},

Expand All @@ -21,55 +25,59 @@ const TaskItem = TipTapTaskItem.extend({
content: 'paragraph block*',

addAttributes() {
const adjust = { ...this.parent() }
const adjust = { ...this.parent?.() }
adjust.checked.parseHTML = (el) => {
return el.querySelector('input[type=checkbox]')?.checked
return (el.querySelector('input[type=checkbox]') as HTMLInputElement)
?.checked
}
return adjust
},

parseHTML: [
{
priority: 101,
tag: 'li',
getAttrs: (el) => {
const checkbox = el.querySelector('input[type=checkbox]')
return checkbox
parseHTML() {
return [
{
priority: 101,
tag: 'li',
getAttrs: (el) => {
const checkbox = el.querySelector('input[type=checkbox]')
return checkbox
},
context: 'taskList/',
},
context: 'taskList/',
},
],
]
},

renderHTML({ node, HTMLAttributes }) {
const listAttributes = { class: 'task-list-item checkbox-item' }
const listAttributes = {
class: `task-list-item checkbox-item${node.attrs.checked ? ' checked' : ''}`,
} as const
const checkboxAttributes = {
type: 'checkbox',
class: '',
contenteditable: false,
}
if (node.attrs.checked) {
checkboxAttributes.checked = true
listAttributes.class += ' checked'
}
...(node.attrs.checked ? { checked: true } : {}),
} as const

return [
'li',
mergeAttributes(HTMLAttributes, listAttributes),
['input', checkboxAttributes],
['label', 0],
['div', { class: 'task-item-content' }, 0],
]
},

// overwrite the parent node view so renderHTML gets used
addNodeView: false,
addNodeView: () => null,

toMarkdown: (state, node) => {
// @ts-expect-error - toMarkdown is a custom field not part of the official Tiptap API
toMarkdown: (state: MarkdownSerializerState, node: Node) => {
state.write(`[${node.attrs.checked ? 'x' : ' '}] `)
state.renderContent(node)
},

addInputRules() {
return [
...this.parent(),
...(this.parent?.() || []),
wrappingInputRule({
find: /^\s*([-+*])\s(\[(x|X|\s)?\])\s$/,
type: this.type,
Expand All @@ -92,18 +100,22 @@ const TaskItem = TipTapTaskItem.extend({
left: event.clientX,
top: event.clientY,
})
if (!coordinates) {
return
}
const position = state.doc.resolve(coordinates.pos)
const parentList = findParentNodeClosestToPos(
position,
function (node) {
function (node: Node) {
return (
node.type === schema.nodes.taskItem
|| node.type === schema.nodes.listItem
)
},
)
const isListClicked =
event.target.tagName.toLowerCase() === 'li'
event.target instanceof Element
&& event.target.tagName.toLowerCase() === 'li'
if (
!isListClicked
|| !parentList
Expand Down
2 changes: 1 addition & 1 deletion src/tests/extensions/Markdown.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Italic, Link, Strong, Underline } from '../../marks/index.js'
import Image from '../../nodes/Image.js'
import OrderedList from '../../nodes/OrderedList.ts'
import Table from '../../nodes/Table.js'
import TaskItem from '../../nodes/TaskItem.js'
import TaskItem from '../../nodes/TaskItem.ts'
import TaskList from '../../nodes/TaskList.ts'
import createCustomEditor from '../testHelpers/createCustomEditor.ts'
import ImageInline from './../../nodes/ImageInline.js'
Expand Down
2 changes: 1 addition & 1 deletion src/tests/nodes/TaskItem.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
markdownThroughEditorHtml,
} from '../testHelpers/markdown.js'
import Markdown from './../../extensions/Markdown.js'
import TaskItem from './../../nodes/TaskItem.js'
import TaskItem from './../../nodes/TaskItem.ts'
import TaskList from './../../nodes/TaskList.ts'

describe('TaskItem extension', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/tests/tiptap.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('TipTap', () => {
it('render taskList', () => {
const markdown = '* [ ] item 1\n'
expect(renderedHTML(markdown)).toEqual(
'<ul class="contains-task-list"><li dir="ltr" data-checked="false" class="task-list-item checkbox-item"><input type="checkbox" class="" contenteditable="false"><label><p dir="ltr">item 1</p></label></li></ul>',
'<ul class="contains-task-list"><li dir="ltr" data-checked="false" class="task-list-item checkbox-item"><input type="checkbox" class="" contenteditable="false"><div class="task-item-content"><p dir="ltr">item 1</p></div></li></ul>',
)
})
})
Loading