diff --git a/docs/src/demos/Extensions/TaskList/index.vue b/docs/src/demos/Extensions/TaskList/index.vue
index bae41d95..06d1f1be 100644
--- a/docs/src/demos/Extensions/TaskList/index.vue
+++ b/docs/src/demos/Extensions/TaskList/index.vue
@@ -39,8 +39,8 @@ export default {
],
content: `
- - A list item
- - And another one
+ - A list item
+ - And another one
`,
})
diff --git a/packages/core/src/ExtensionManager.ts b/packages/core/src/ExtensionManager.ts
index 2d27f087..23b91aac 100644
--- a/packages/core/src/ExtensionManager.ts
+++ b/packages/core/src/ExtensionManager.ts
@@ -8,6 +8,8 @@ import { Extensions, NodeViewRenderer } from './types'
import getSchema from './utils/getSchema'
import getSchemaTypeByName from './utils/getSchemaTypeByName'
import splitExtensions from './utils/splitExtensions'
+import getAttributesFromExtensions from './utils/getAttributesFromExtensions'
+import getRenderedAttributes from './utils/getRenderedAttributes'
export default class ExtensionManager {
@@ -97,14 +99,17 @@ export default class ExtensionManager {
}
get nodeViews() {
+ const { editor } = this
const { nodeExtensions } = splitExtensions(this.extensions)
+ const allAttributes = getAttributesFromExtensions(this.extensions)
return Object.fromEntries(nodeExtensions
.filter(extension => !!extension.addNodeView)
.map(extension => {
+ const extensionAttributes = allAttributes.filter(attribute => attribute.type === extension.name)
const context = {
options: extension.options,
- editor: this.editor,
+ editor,
type: getSchemaTypeByName(extension.name, this.schema),
}
@@ -115,12 +120,17 @@ export default class ExtensionManager {
view: EditorView,
getPos: (() => number) | boolean,
decorations: Decoration[],
- ) => renderer({
- editor: this.editor,
- node,
- getPos,
- decorations,
- })
+ ) => {
+ const attributes = getRenderedAttributes(node, extensionAttributes)
+
+ return renderer({
+ editor,
+ node,
+ getPos,
+ decorations,
+ attributes,
+ })
+ }
return [extension.name, nodeview]
}))
diff --git a/packages/core/src/extensions/toggleList.ts b/packages/core/src/extensions/toggleList.ts
index 2f7a15d3..26f97ea5 100644
--- a/packages/core/src/extensions/toggleList.ts
+++ b/packages/core/src/extensions/toggleList.ts
@@ -8,7 +8,7 @@ import getNodeType from '../utils/getNodeType'
function isList(node: Node, schema: Schema) {
return (node.type === schema.nodes.bullet_list
|| node.type === schema.nodes.ordered_list
- || node.type === schema.nodes.todo_list)
+ || node.type === schema.nodes.task_list)
}
export const ToggleList = createExtension({
diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts
index d1385106..e0f09679 100644
--- a/packages/core/src/types.ts
+++ b/packages/core/src/types.ts
@@ -48,7 +48,8 @@ export type NodeViewRendererProps = {
editor: Editor,
node: Node,
getPos: (() => number) | boolean,
- decorations: Decoration[]
+ decorations: Decoration[],
+ attributes: AnyObject,
}
export type NodeViewRenderer = (props: NodeViewRendererProps) => NodeView
diff --git a/packages/core/src/utils/getRenderedAttributes.ts b/packages/core/src/utils/getRenderedAttributes.ts
index da92012d..48fd7021 100644
--- a/packages/core/src/utils/getRenderedAttributes.ts
+++ b/packages/core/src/utils/getRenderedAttributes.ts
@@ -1,8 +1,8 @@
import { Node, Mark } from 'prosemirror-model'
-import { ExtensionAttribute } from '../types'
+import { ExtensionAttribute, AnyObject } from '../types'
import mergeAttributes from './mergeAttributes'
-export default function getRenderedAttributes(nodeOrMark: Node | Mark, extensionAttributes: ExtensionAttribute[]): { [key: string]: any } {
+export default function getRenderedAttributes(nodeOrMark: Node | Mark, extensionAttributes: ExtensionAttribute[]): AnyObject {
return extensionAttributes
.filter(item => item.attribute.rendered)
.map(item => {
diff --git a/packages/extension-task-item/index.ts b/packages/extension-task-item/index.ts
index 6ac32943..283296cf 100644
--- a/packages/extension-task-item/index.ts
+++ b/packages/extension-task-item/index.ts
@@ -22,8 +22,14 @@ const TaskItem = createNode({
addAttributes() {
return {
- done: {
+ checked: {
default: false,
+ parseHTML: element => ({
+ checked: element.getAttribute('data-checked') === 'true',
+ }),
+ renderHTML: attributes => ({
+ 'data-checked': attributes.checked,
+ }),
},
}
},
@@ -42,12 +48,55 @@ const TaskItem = createNode({
},
addKeyboardShortcuts() {
- return {
+ const shortcuts = {
Enter: () => this.editor.splitListItem('task_item'),
+ }
+
+ if (!this.options.nested) {
+ return shortcuts
+ }
+
+ return {
+ ...shortcuts,
Tab: () => this.editor.sinkListItem('task_item'),
'Shift-Tab': () => this.editor.liftListItem('task_item'),
}
},
+
+ addNodeView() {
+ return ({ attributes, getPos, editor }) => {
+ 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,
+ }))
+ }
+ })
+
+ if (attributes['data-checked'] === true) {
+ checkbox.setAttribute('checked', 'checked')
+ }
+
+ listItem.append(checkbox, content)
+
+ Object.entries(attributes).forEach(([key, value]) => {
+ listItem.setAttribute(key, value)
+ })
+
+ return {
+ dom: listItem,
+ contentDOM: content,
+ }
+ }
+ },
})
export default TaskItem