add node view to task item
This commit is contained in:
@@ -39,8 +39,8 @@ export default {
|
|||||||
],
|
],
|
||||||
content: `
|
content: `
|
||||||
<ul data-type="task_list">
|
<ul data-type="task_list">
|
||||||
<li>A list item</li>
|
<li data-type="task_item" data-checked="true">A list item</li>
|
||||||
<li>And another one</li>
|
<li data-type="task_item" data-checked="false">And another one</li>
|
||||||
</ul>
|
</ul>
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { Extensions, NodeViewRenderer } from './types'
|
|||||||
import getSchema from './utils/getSchema'
|
import getSchema from './utils/getSchema'
|
||||||
import getSchemaTypeByName from './utils/getSchemaTypeByName'
|
import getSchemaTypeByName from './utils/getSchemaTypeByName'
|
||||||
import splitExtensions from './utils/splitExtensions'
|
import splitExtensions from './utils/splitExtensions'
|
||||||
|
import getAttributesFromExtensions from './utils/getAttributesFromExtensions'
|
||||||
|
import getRenderedAttributes from './utils/getRenderedAttributes'
|
||||||
|
|
||||||
export default class ExtensionManager {
|
export default class ExtensionManager {
|
||||||
|
|
||||||
@@ -97,14 +99,17 @@ export default class ExtensionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get nodeViews() {
|
get nodeViews() {
|
||||||
|
const { editor } = this
|
||||||
const { nodeExtensions } = splitExtensions(this.extensions)
|
const { nodeExtensions } = splitExtensions(this.extensions)
|
||||||
|
const allAttributes = getAttributesFromExtensions(this.extensions)
|
||||||
|
|
||||||
return Object.fromEntries(nodeExtensions
|
return Object.fromEntries(nodeExtensions
|
||||||
.filter(extension => !!extension.addNodeView)
|
.filter(extension => !!extension.addNodeView)
|
||||||
.map(extension => {
|
.map(extension => {
|
||||||
|
const extensionAttributes = allAttributes.filter(attribute => attribute.type === extension.name)
|
||||||
const context = {
|
const context = {
|
||||||
options: extension.options,
|
options: extension.options,
|
||||||
editor: this.editor,
|
editor,
|
||||||
type: getSchemaTypeByName(extension.name, this.schema),
|
type: getSchemaTypeByName(extension.name, this.schema),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,12 +120,17 @@ export default class ExtensionManager {
|
|||||||
view: EditorView,
|
view: EditorView,
|
||||||
getPos: (() => number) | boolean,
|
getPos: (() => number) | boolean,
|
||||||
decorations: Decoration[],
|
decorations: Decoration[],
|
||||||
) => renderer({
|
) => {
|
||||||
editor: this.editor,
|
const attributes = getRenderedAttributes(node, extensionAttributes)
|
||||||
|
|
||||||
|
return renderer({
|
||||||
|
editor,
|
||||||
node,
|
node,
|
||||||
getPos,
|
getPos,
|
||||||
decorations,
|
decorations,
|
||||||
|
attributes,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return [extension.name, nodeview]
|
return [extension.name, nodeview]
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import getNodeType from '../utils/getNodeType'
|
|||||||
function isList(node: Node, schema: Schema) {
|
function isList(node: Node, schema: Schema) {
|
||||||
return (node.type === schema.nodes.bullet_list
|
return (node.type === schema.nodes.bullet_list
|
||||||
|| node.type === schema.nodes.ordered_list
|
|| node.type === schema.nodes.ordered_list
|
||||||
|| node.type === schema.nodes.todo_list)
|
|| node.type === schema.nodes.task_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ToggleList = createExtension({
|
export const ToggleList = createExtension({
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ export type NodeViewRendererProps = {
|
|||||||
editor: Editor,
|
editor: Editor,
|
||||||
node: Node,
|
node: Node,
|
||||||
getPos: (() => number) | boolean,
|
getPos: (() => number) | boolean,
|
||||||
decorations: Decoration[]
|
decorations: Decoration[],
|
||||||
|
attributes: AnyObject,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NodeViewRenderer = (props: NodeViewRendererProps) => NodeView
|
export type NodeViewRenderer = (props: NodeViewRendererProps) => NodeView
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Node, Mark } from 'prosemirror-model'
|
import { Node, Mark } from 'prosemirror-model'
|
||||||
import { ExtensionAttribute } from '../types'
|
import { ExtensionAttribute, AnyObject } from '../types'
|
||||||
import mergeAttributes from './mergeAttributes'
|
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
|
return extensionAttributes
|
||||||
.filter(item => item.attribute.rendered)
|
.filter(item => item.attribute.rendered)
|
||||||
.map(item => {
|
.map(item => {
|
||||||
|
|||||||
@@ -22,8 +22,14 @@ const TaskItem = createNode({
|
|||||||
|
|
||||||
addAttributes() {
|
addAttributes() {
|
||||||
return {
|
return {
|
||||||
done: {
|
checked: {
|
||||||
default: false,
|
default: false,
|
||||||
|
parseHTML: element => ({
|
||||||
|
checked: element.getAttribute('data-checked') === 'true',
|
||||||
|
}),
|
||||||
|
renderHTML: attributes => ({
|
||||||
|
'data-checked': attributes.checked,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -42,12 +48,55 @@ const TaskItem = createNode({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addKeyboardShortcuts() {
|
addKeyboardShortcuts() {
|
||||||
return {
|
const shortcuts = {
|
||||||
Enter: () => this.editor.splitListItem('task_item'),
|
Enter: () => this.editor.splitListItem('task_item'),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.options.nested) {
|
||||||
|
return shortcuts
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...shortcuts,
|
||||||
Tab: () => this.editor.sinkListItem('task_item'),
|
Tab: () => this.editor.sinkListItem('task_item'),
|
||||||
'Shift-Tab': () => this.editor.liftListItem('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
|
export default TaskItem
|
||||||
|
|||||||
Reference in New Issue
Block a user