mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-06-14 22:32:24 +08:00
feat: allow support for drag-and-drop between multiple editors (#5893)
* feat: drag and drop across multi editors * feat: drag and drop across multi editors optimize * feat: drag and drop across multi editors optimize * added changeset --------- Co-authored-by: songhandong <songhandong@baidu.com> Co-authored-by: songispm <38745323+songispm@users.noreply.github.com> Co-authored-by: songispm <songispm@gmail.com>
This commit is contained in:
parent
01547d5b2f
commit
ca6269e928
5
.changeset/many-glasses-reflect.md
Normal file
5
.changeset/many-glasses-reflect.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@tiptap/core": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Added support for drag-and-drop between multiple editors
|
@ -44,7 +44,8 @@ export default Extension.create({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dragStart(e, view) {
|
function dragStart(e, view) {
|
||||||
view.composing = true
|
// Must delete this line, Otherwise: Uncaught TypeError: Cannot set property composing of #<EditorView> which has only a getter
|
||||||
|
// view.composing = true
|
||||||
|
|
||||||
if (!e.dataTransfer) {
|
if (!e.dataTransfer) {
|
||||||
return
|
return
|
||||||
@ -75,6 +76,11 @@ export default Extension.create({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dragEnd(e, view) {
|
||||||
|
// reset the dragging, otherwise wrong content after dragging across multi editors repeatedly
|
||||||
|
view.dragging = null
|
||||||
|
}
|
||||||
|
|
||||||
let dropElement
|
let dropElement
|
||||||
const WIDTH = 28
|
const WIDTH = 28
|
||||||
|
|
||||||
@ -86,8 +92,10 @@ export default Extension.create({
|
|||||||
element.draggable = 'true'
|
element.draggable = 'true'
|
||||||
element.classList.add('global-drag-handle')
|
element.classList.add('global-drag-handle')
|
||||||
element.addEventListener('dragstart', e => dragStart(e, editorView))
|
element.addEventListener('dragstart', e => dragStart(e, editorView))
|
||||||
|
element.addEventListener('dragend', e => dragEnd(e, editorView))
|
||||||
dropElement = element
|
dropElement = element
|
||||||
document.body.appendChild(dropElement)
|
// append to editor's parentNode (not document.body), to match the logic of dragging across multi editors in pasteRule.ts
|
||||||
|
editorView.dom.parentNode.appendChild(dropElement)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// update(view, prevState) {
|
// update(view, prevState) {
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
import Bold from '@tiptap/extension-bold'
|
import Bold from '@tiptap/extension-bold'
|
||||||
import Collaboration from '@tiptap/extension-collaboration'
|
import Collaboration from '@tiptap/extension-collaboration'
|
||||||
import Document from '@tiptap/extension-document'
|
import Document from '@tiptap/extension-document'
|
||||||
|
import DropCursor from '@tiptap/extension-dropcursor'
|
||||||
import Heading from '@tiptap/extension-heading'
|
import Heading from '@tiptap/extension-heading'
|
||||||
import Paragraph from '@tiptap/extension-paragraph'
|
import Paragraph from '@tiptap/extension-paragraph'
|
||||||
import TaskItem from '@tiptap/extension-task-item'
|
import TaskItem from '@tiptap/extension-task-item'
|
||||||
@ -75,6 +76,8 @@ export default {
|
|||||||
levels: [2],
|
levels: [2],
|
||||||
}),
|
}),
|
||||||
Text,
|
Text,
|
||||||
|
Bold,
|
||||||
|
DropCursor,
|
||||||
Collaboration.configure({
|
Collaboration.configure({
|
||||||
document: this.ydoc,
|
document: this.ydoc,
|
||||||
field: 'title',
|
field: 'title',
|
||||||
@ -88,6 +91,8 @@ export default {
|
|||||||
TaskListDocument,
|
TaskListDocument,
|
||||||
Paragraph,
|
Paragraph,
|
||||||
Text,
|
Text,
|
||||||
|
Bold,
|
||||||
|
DropCursor,
|
||||||
TaskList,
|
TaskList,
|
||||||
CustomTaskItem,
|
CustomTaskItem,
|
||||||
Collaboration.configure({
|
Collaboration.configure({
|
||||||
@ -110,6 +115,7 @@ export default {
|
|||||||
Paragraph,
|
Paragraph,
|
||||||
Text,
|
Text,
|
||||||
Bold,
|
Bold,
|
||||||
|
DropCursor,
|
||||||
Collaboration.configure({
|
Collaboration.configure({
|
||||||
document: this.ydoc,
|
document: this.ydoc,
|
||||||
field: 'description',
|
field: 'description',
|
||||||
|
@ -162,6 +162,9 @@ function run(config: {
|
|||||||
return success
|
return success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When dragging across editors, must get another editor instance to delete selection content.
|
||||||
|
let tiptapDragFromOtherEditor: Editor | null = null
|
||||||
|
|
||||||
const createClipboardPasteEvent = (text: string) => {
|
const createClipboardPasteEvent = (text: string) => {
|
||||||
const event = new ClipboardEvent('paste', {
|
const event = new ClipboardEvent('paste', {
|
||||||
clipboardData: new DataTransfer(),
|
clipboardData: new DataTransfer(),
|
||||||
@ -242,13 +245,25 @@ export function pasteRulesPlugin(props: { editor: Editor; rules: PasteRule[] }):
|
|||||||
dragSourceElement = view.dom.parentElement?.contains(event.target as Element)
|
dragSourceElement = view.dom.parentElement?.contains(event.target as Element)
|
||||||
? view.dom.parentElement
|
? view.dom.parentElement
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
if (dragSourceElement) {
|
||||||
|
tiptapDragFromOtherEditor = editor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDragend = () => {
|
||||||
|
if (tiptapDragFromOtherEditor) {
|
||||||
|
tiptapDragFromOtherEditor = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('dragstart', handleDragstart)
|
window.addEventListener('dragstart', handleDragstart)
|
||||||
|
window.addEventListener('dragend', handleDragend)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
destroy() {
|
destroy() {
|
||||||
window.removeEventListener('dragstart', handleDragstart)
|
window.removeEventListener('dragstart', handleDragstart)
|
||||||
|
window.removeEventListener('dragend', handleDragend)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -259,6 +274,20 @@ export function pasteRulesPlugin(props: { editor: Editor; rules: PasteRule[] }):
|
|||||||
isDroppedFromProseMirror = dragSourceElement === view.dom.parentElement
|
isDroppedFromProseMirror = dragSourceElement === view.dom.parentElement
|
||||||
dropEvent = event as DragEvent
|
dropEvent = event as DragEvent
|
||||||
|
|
||||||
|
if (!isDroppedFromProseMirror) {
|
||||||
|
const dragFromOtherEditor = tiptapDragFromOtherEditor
|
||||||
|
|
||||||
|
if (dragFromOtherEditor) {
|
||||||
|
// setTimeout to avoid the wrong content after drop, timeout arg can't be empty or 0
|
||||||
|
setTimeout(() => {
|
||||||
|
const selection = dragFromOtherEditor.state.selection
|
||||||
|
|
||||||
|
if (selection) {
|
||||||
|
dragFromOtherEditor.commands.deleteRange({ from: selection.from, to: selection.to })
|
||||||
|
}
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user