rjaros / kvision

Object oriented web framework for Kotlin/JS
https://kvision.io
MIT License
1.2k stars 66 forks source link

Request - add Widget level drag & drop #492

Open reubenfirmin opened 8 months ago

reubenfirmin commented 8 months ago

I found https://kvision.gitbook.io/kvision-guide/2.-frontend-development-guide/drag-and-drop pretty hard to understand. Looking at the source, it seems that this is thin shim on top of data transfer, but it doesn't work at the same level of abstraction as the rest of kvision (since we're expected to handle serialization/deserialization directly).

The other problem, I think, is that serialization happens on initial render, rather than at the start of the drag event, which is relatively expensive (and also doesn't allow for dynamic updates without updating setDragTargetData) -- i.e. there is no way to set "draggable = true" without also setting the serialized data that gets pushed into datatransfer.

It would be great to provide a set of generic (maybe inline/reified) functions that handle conversion to and from Widget subclasses.

It would also be really nice to be able to hook into some of the lifecyle events of drag and drop. I'm using dragula right now, which is sadly unmaintained; however it has a nice API that could be emulated: https://github.com/bevacqua/dragula/

rjaros commented 8 months ago

You are thinking about direct drag & drop of KVision widgets?

reubenfirmin commented 8 months ago

Right. So for example:

class MyComponent: Div() {

     init {
         setDropTarget(true)
     }

     // only called if canDrop returns true - dragula supports this
     override fun onDrop(widget: Widget) {

     }  

     // nice to have -  gives the widget the thing that's potentially going to be dropped, so a preview can be rendered (like trello)
     override fun onDragOver(widget: Widget) {

      }

     // matches above
     override fun onDragOut(widget: Widget) {

      }

     // similar to dragula. this is really useful, as it lets you ignore draggables that aren't applicable to this drop target
     override fun canDrop(widget: Widget): Boolean {
          return if (widget is MyOtherComponent && ((widget as MyOtherComponent).someProperty == "foo") {
               true
          } else {
               false
          }
     }
}
class MyOtherComponent: Div() {
      init { 
          setDraggable(true)
      } 
}