tiptap/packages/extension-task-item/src/index.ts

129 lines
2.7 KiB
TypeScript
Raw Normal View History

import { createNode, mergeAttributes } from '@tiptap/core'
import { wrappingInputRule } from 'prosemirror-inputrules'
export const inputRegex = /^\s*(\[([ |x])\])\s$/
export interface TaskItemOptions {
nested: boolean,
}
const TaskItem = createNode({
2020-11-04 03:57:09 +08:00
name: 'taskItem',
content() {
2020-11-05 21:51:34 +08:00
return this.options.nested ? '(paragraph|taskList)+' : 'paragraph+'
},
defining: true,
defaultOptions: <TaskItemOptions>{
nested: false,
},
addAttributes() {
return {
2020-10-30 21:55:48 +08:00
checked: {
default: false,
2020-10-30 21:55:48 +08:00
parseHTML: element => ({
checked: element.getAttribute('data-checked') === 'true',
}),
renderHTML: attributes => ({
'data-checked': attributes.checked,
}),
},
}
},
parseHTML() {
return [
{
2020-11-04 03:57:09 +08:00
tag: 'li[data-type="taskItem"]',
priority: 51,
},
]
},
2020-11-13 23:07:20 +08:00
renderHTML({ HTMLAttributes }) {
return ['li', mergeAttributes(HTMLAttributes, { 'data-type': 'taskItem' }), 0]
},
addKeyboardShortcuts() {
2020-10-30 21:55:48 +08:00
const shortcuts = {
Enter: () => this.editor.commands.splitListItem('taskItem'),
'Shift-Tab': () => this.editor.commands.liftListItem('taskItem'),
2020-10-30 21:55:48 +08:00
}
if (!this.options.nested) {
return shortcuts
}
return {
...shortcuts,
Tab: () => this.editor.commands.sinkListItem('taskItem'),
}
},
2020-10-30 21:55:48 +08:00
addNodeView() {
2020-11-13 23:07:20 +08:00
return ({ HTMLAttributes, getPos, editor }) => {
2020-10-30 21:55:48 +08:00
const { view } = editor
const listItem = document.createElement('li')
const checkbox = document.createElement('input')
const content = document.createElement('div')
checkbox.type = 'checkbox'
checkbox.addEventListener('change', event => {
const { checked } = event.target as any
if (typeof getPos === 'function') {
view.dispatch(view.state.tr.setNodeMarkup(getPos(), undefined, {
checked,
}))
editor.commands.focus()
2020-10-30 21:55:48 +08:00
}
})
2020-11-13 23:07:20 +08:00
if (HTMLAttributes['data-checked'] === true) {
2020-10-30 21:55:48 +08:00
checkbox.setAttribute('checked', 'checked')
}
listItem.append(checkbox, content)
2020-11-13 23:07:20 +08:00
Object.entries(HTMLAttributes).forEach(([key, value]) => {
2020-10-30 21:55:48 +08:00
listItem.setAttribute(key, value)
})
return {
dom: listItem,
contentDOM: content,
update: node => {
if (node.type !== this.type) {
return false
}
return true
},
2020-10-30 21:55:48 +08:00
}
}
},
addInputRules() {
return [
wrappingInputRule(
inputRegex,
this.type,
match => ({
checked: match[match.length - 1] === 'x',
}),
),
]
},
})
export default TaskItem
2020-11-11 04:18:22 +08:00
declare module '@tiptap/core' {
interface AllExtensions {
TaskItem: typeof TaskItem,
}
}