webapp/src/components/Editor/prosemirror/extension/drag-handle.ts

54 lines
1.7 KiB
TypeScript
Raw Normal View History

2022-09-09 11:53:35 +00:00
import { Plugin, NodeSelection } from 'prosemirror-state'
import { DecorationSet, Decoration } from 'prosemirror-view'
2022-10-19 17:26:07 +00:00
import { ProseMirrorExtension } from '../helpers'
const handleIcon = `
<svg viewBox="0 0 10 10" height="14" width="14">
<path d="M3 2a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2zm4-8a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2z"/>
</svg>`
2022-09-09 11:53:35 +00:00
const createDragHandle = () => {
const handle = document.createElement('span')
handle.setAttribute('contenteditable', 'false')
const icon = document.createElement('span')
icon.innerHTML = handleIcon
2022-10-09 00:00:13 +00:00
handle.appendChild(icon)
2022-09-09 11:53:35 +00:00
handle.classList.add('handle')
return handle
}
const handlePlugin = new Plugin({
props: {
decorations(state) {
const decos = []
state.doc.forEach((node, pos) => {
2022-10-19 17:26:07 +00:00
decos.push(Decoration.widget(pos + 1, createDragHandle))
2022-09-09 11:53:35 +00:00
decos.push(
Decoration.node(pos, pos + node.nodeSize, {
class: 'draggable'
})
)
})
return DecorationSet.create(state.doc, decos)
},
handleDOMEvents: {
mousedown: (editorView, event) => {
const target = event.target as Element
if (target.classList.contains('handle')) {
const pos = editorView.posAtCoords({ left: event.x, top: event.y })
const resolved = editorView.state.doc.resolve(pos.pos)
const tr = editorView.state.tr
tr.setSelection(NodeSelection.create(editorView.state.doc, resolved.before()))
editorView.dispatch(tr)
return false
}
}
}
}
})
export default (): ProseMirrorExtension => ({
plugins: (prev) => [...prev, handlePlugin]
})