Files
tiptap/packages/tiptap-extensions/src/nodes/TodoItem.js
2020-01-06 15:13:20 -07:00

109 lines
2.7 KiB
JavaScript

import { Node } from 'tiptap'
import { sinkListItem, splitToDefaultListItem, liftListItem } from 'tiptap-commands'
export default class TodoItem extends Node {
get name() {
return 'todo_item'
}
get defaultOptions() {
return {
nested: false,
}
}
get view() {
return {
props: ['node', 'updateAttrs', 'view'],
methods: {
onChange() {
this.updateAttrs({
done: !this.node.attrs.done,
})
},
},
template: `
<li :data-type="node.type.name" :data-done="node.attrs.done.toString()" data-drag-handle>
<span class="todo-checkbox" contenteditable="false" @click="onChange"></span>
<div class="todo-content" ref="content" :contenteditable="view.editable.toString()"></div>
</li>
`,
/*
The render function enables TodoItem to work in `runtimeonly` builds,
which is required for frameworks requiring strict CSP policies. For
example, doing this is required in Chrome Extensions. Having both
the template and the render function ensures there are no issues
converting the node to JSON and rendering the component.
*/
render(h) {
return h('li', {
attrs: {
'data-type': this.node.type.name,
'data-done': this.node.attrs.done.toString(),
'data-drag-handle': '',
},
}, [
h('span', {
class: 'todo-checkbox',
attrs: {
contenteditable: false,
},
on: {
click: this.onChange,
},
}),
h('div', {
class: 'todo-content',
attrs: {
contenteditable: this.view.editable.toString(),
},
ref: 'content',
}),
])
},
}
}
get schema() {
return {
attrs: {
done: {
default: false,
},
},
draggable: true,
content: this.options.nested ? '(paragraph|todo_list)+' : 'paragraph+',
toDOM: node => {
const { done } = node.attrs
return [
'li',
{
'data-type': this.name,
'data-done': done.toString(),
},
['span', { class: 'todo-checkbox', contenteditable: 'false' }],
['div', { class: 'todo-content' }, 0],
]
},
parseDOM: [{
priority: 51,
tag: `[data-type="${this.name}"]`,
getAttrs: dom => ({
done: dom.getAttribute('data-done') === 'true',
}),
}],
}
}
keys({ type }) {
return {
Enter: splitToDefaultListItem(type),
Tab: this.options.nested ? sinkListItem(type) : () => {},
'Shift-Tab': liftListItem(type),
}
}
}