We have almost finished our builder, almost the most important thing remains, this is drag and drop!
Chameleon provides two wrapper components for implementing drag and drop, these are Draggable and Dropzone
Draggable - what we drag
Dropzone - area where blocks can be dropped
There is also a hook view.dragAndDrop.useBlockState(block) which provides information about whether the dragged block is currently located above the block or whether the block is available for dropping a block into it
Root
Let’s look at an example of integrating drag and drop into the Root block
As you can see, we simply wrap our children in a Dropzone and pass our block to props
Please note that Dropzone requires that the child be of type ReactElement and be able to accept ref, so we wrapped our children in div
Paper
Paper is already draggable and has Dropzone
Here we already wrap the block in the Draggable component to which we pass the id of our block, because of this, the internal Dropzone no longer needs to forward the block since it will take it from Draggable
Using the result of useBlockState we also add various highlight effects, but writing this every time can be tedious, let’s move this logic into a separate hook
It already looks better
Stack
Stack is just like Paper
Text
Text can only be dragged and dropped
TextField
TextField has a more complex case
In this case we couldn’t just do
Because the Controller does not accept ref, for such cases Draggable can use render prop for children, the arguments we receive is an object { ref, attrs, listeners, style } whose values we must pass to the component that will be Draggable
We also passed the ref to Draggable, this ref will be combined with the ref for Draggable and passed to the render prop
This is done in order not to have to manually combine refs for transfer to the component, as in our component, we have one ref for Popover and a second for Draggable