Skip to content

Commit

Permalink
feat: allow support for drag-and-drop between multiple editors (ueber…
Browse files Browse the repository at this point in the history
…dosis#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>
  • Loading branch information
4 people authored Nov 30, 2024
1 parent 01547d5 commit ca6269e
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/many-glasses-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tiptap/core": patch
---

Added support for drag-and-drop between multiple editors
12 changes: 10 additions & 2 deletions demos/src/Experiments/GlobalDragHandle/Vue/DragHandle.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ export default Extension.create({
}

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) {
return
Expand Down Expand Up @@ -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
const WIDTH = 28

Expand All @@ -86,8 +92,10 @@ export default Extension.create({
element.draggable = 'true'
element.classList.add('global-drag-handle')
element.addEventListener('dragstart', e => dragStart(e, editorView))
element.addEventListener('dragend', e => dragEnd(e, editorView))
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 {
// update(view, prevState) {
Expand Down
6 changes: 6 additions & 0 deletions demos/src/Experiments/MultipleEditors/Vue/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import Bold from '@tiptap/extension-bold'
import Collaboration from '@tiptap/extension-collaboration'
import Document from '@tiptap/extension-document'
import DropCursor from '@tiptap/extension-dropcursor'
import Heading from '@tiptap/extension-heading'
import Paragraph from '@tiptap/extension-paragraph'
import TaskItem from '@tiptap/extension-task-item'
Expand Down Expand Up @@ -75,6 +76,8 @@ export default {
levels: [2],
}),
Text,
Bold,
DropCursor,
Collaboration.configure({
document: this.ydoc,
field: 'title',
Expand All @@ -88,6 +91,8 @@ export default {
TaskListDocument,
Paragraph,
Text,
Bold,
DropCursor,
TaskList,
CustomTaskItem,
Collaboration.configure({
Expand All @@ -110,6 +115,7 @@ export default {
Paragraph,
Text,
Bold,
DropCursor,
Collaboration.configure({
document: this.ydoc,
field: 'description',
Expand Down
29 changes: 29 additions & 0 deletions packages/core/src/PasteRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ function run(config: {
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 event = new ClipboardEvent('paste', {
clipboardData: new DataTransfer(),
Expand Down Expand Up @@ -242,13 +245,25 @@ export function pasteRulesPlugin(props: { editor: Editor; rules: PasteRule[] }):
dragSourceElement = view.dom.parentElement?.contains(event.target as Element)
? view.dom.parentElement
: null

if (dragSourceElement) {
tiptapDragFromOtherEditor = editor
}
}

const handleDragend = () => {
if (tiptapDragFromOtherEditor) {
tiptapDragFromOtherEditor = null
}
}

window.addEventListener('dragstart', handleDragstart)
window.addEventListener('dragend', handleDragend)

return {
destroy() {
window.removeEventListener('dragstart', handleDragstart)
window.removeEventListener('dragend', handleDragend)
},
}
},
Expand All @@ -259,6 +274,20 @@ export function pasteRulesPlugin(props: { editor: Editor; rules: PasteRule[] }):
isDroppedFromProseMirror = dragSourceElement === view.dom.parentElement
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
},

Expand Down

0 comments on commit ca6269e

Please sign in to comment.