Drag'n'Drop - a drag handle element

Hi, guys

I spent much time on understanding how to create a drag handle element. I need it only for top-level nodes. I looked at the documentation and other topics but I can’t understand how to do it.

I thought about the controlling the drag state by controlling the HTML draggable property but the ProseMirror doesn’t use it.
I thought about creating an additional schema type (wrapper with a drag handle element) but then the behaviour won’t be obvious because wrapper must be only on top level elements, when transforming or moving between levels, it would be necessary to keep an eye on this.
I thought about creating an independent drag handle element (I don’t have much experience with d’n’d) and about working around the DataTransfer api, maybe this is what I need.

What is the correct way to create a drag handle element?

The easiest way to do this is to make your drag handle set a node selection around the node you want to drag on mousedown (make sure the node is selectable). Something like this (can leave out the contentDOM and contentEditable stuff if your node is a leaf node):

class MyNodeView {
  constructor(node, view, getPos) {
    this.dom = document.createElement("div");
    this.dom.style.cssText = "position: relative"
    this.drag = this.dom.appendChild(document.createElement("div"))
    this.drag.style.cssText = "border: 1px solid grey; width: 10px; height: 20px; position: absolute; left: -10px; cursor: grab"
    this.drag.contentEditable = false
    this.drag.onmousedown = e => {
      if (e.button == 0)
        view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, getPos())))
    }
    this.contentDOM = this.dom.appendChild(document.createElement("div"))
  }
}
1 Like

Does this way mean that every node must have a wrapper with the drag handle element?

I need to have the drag handle element only for top-level nodes, It means that If I use this method I’ll must control all transformations. If the element gets to the top level, I’ll have to make sure that it’s wrapped with a wrapper. If the element gets to the child level, I’ll have to make sure that the wrapper is removed. I’ll always need to take this into account.

I tried to create a widget with your logic but It just selected a node without the d’n’d behaviour (which is predictable xd)

If someone knows about this I’d be glad of your help

@lunar616 I’m working on something similar. Were you able to finish this feature? If so, could you describe your approach?