dnd-kit
dnd-kit copied to clipboard
Consider adding Clone from List example
A popular use-case for DnD is to drag Draggables from a static list to a Sortable Droppable as in a block-based page builder. Consider adding example to the Storybook to achieve this.
This is actually the use-case I'm working on. I have a set of draggables and then a vertical sortable list. Is the strategy here to clone the elements you pick up?
I've gotten pretty far with this strategy on cloning. It doesn't feel the most pure but is working in many standard cases. I've distilled down the steps and the complexities of my logic since I'm doing multiple item selection/dragging/dropping as well in many thanks to @henryyi and this PR: https://github.com/clauderic/dnd-kit/pull/13
- Creating a
sortableIdon my objects that I am DnD with https://www.npmjs.com/package/nanoid - Droppable container for the source draggables (Container A)
- Sortable container for the destination container (Container B)
DnDContext:onDragStart: only filter out the items if theactiveis not in (Container A)onDragOver: ifovercontainer (Container B) andactivecontainer (Container A) then generate a newsortableIdfor the item in (Container A) and insert the item into (Container B) at the index.onDragEnd: ifoveroractiveis in (Container A) then NOOP and return. Otherwise move the items of (Container B).setItems((items) => ({ ...items, [overContainer]: move(items[overContainer], activeIndex, overIndex), }));
Are you cloning the item you pick up onDragStart?
I'm using the same setup as you (except I don't have a Droppable wrapping my source draggables). My problem is when I drop an item onto my sortable - it's still linked to my source element. So when I pick it up on the destination container, the source container still thinks I'm picking it up as well. If I "delete" it from my destination container, then my dragging is completely broken. I'm guessing I need to clone it, but not sure how to go about that. I can try to create a codesandbox with my basic setup.
The cloning happens onDragOver in this step:
if over container (Container B) and active container (Container A) then generate a new sortableId for the item in (Container A) and insert the item into (Container B) at the index.
I found it was easier to create a new sortableId on the object that was being cloned from then the new object.
It seems that dnd-kit is built internally upon id as being the unique representation of the object. I had to map the sortableId to fit this construct.
const {
setNodeRef,
listeners,
isDragging,
isSorting,
over,
overIndex,
transform,
transition,
} = useSortable({
id: sortableId,
});
...```
Thanks I got this to work. My mistake was not pay attention and using ids that conflicted.
Did y'all eventually come up with an example for cloning? This is the most beautiful library, but I need to clone!
Circling back on this a few months later to see if anyone has achieved this yet in a more succinct way then I had originally propositioned?
I'm also interested by a small example for this use case, it would be very useful for everyone.
Cloning was pretty easy for me:
import _ from "lodash"
interface ToolElement {
id: string;
type: string;
title: string;
}
// make sure this is within your functional component. You need a new _.uniqueId() each time.
const toolItems: ToolElement[] = [
{ id: _.uniqueId(), type: 'Table', title: "Table" },
{ id: _.uniqueId(), type: 'Form', title: "Form" },
{ id: _.uniqueId(), type: 'Map', title: "Map" },
];
{toolItems.map((tool) => (
<DraggableToolItem key={tool.type} {...tool} />
))}
I used a DragOverlay to render the css.
Hi @ZipBrandon / @mbalex99 -- might either of you be able to provide a codesandbox demonstrating cloning? Would be much appreciated.
I'm also looking into implementing cloning. It'd be great if an example was added to Storybook.
Been looking for a solution regarding cloning. This is my implementation regarding to cloning with this library. Hope this helps other people looking to do the same.
https://codesandbox.io/s/distracted-mendel-hibbgu
Regards
Been looking for a solution regarding cloning. This is my implementation regarding to cloning with this library. Hope this helps other people looking to do the same.
codesandbox.io/s/distracted-mendel-hibbgu
Regards
- there is no cloning in your example;
- maybe u ignored the
useDroppablerelated code
Been looking for a solution regarding cloning. This is my implementation regarding to cloning with this library. Hope this helps other people looking to do the same. codesandbox.io/s/distracted-mendel-hibbgu Regards
- there is no cloning in your example;
- maybe u ignored the
useDroppablerelated code
~~Yes sorry, the droppable is up to you to implement. The example only shows the draggable portion~~
I've updated the example to include droppable area.
Hi @penleychan
Can we use SortableContext inside DroppableArea? and if so is there any example of it?
Thank you.
The problem of cloning the id from the "Bank" container on handleDragOver or handleDragStart cause a full rerender of the Bank component. This feel bad, especially with large amount of items.
I'm trying to achieve the clone in the other way, like on handleDragStart cloning the id of the dragged item directly, this allow to not rerender anything in theory, but I'm currently struggle to achieve that.
Anyone may have an idea ?
For my own project, after looking through this and a few other threads, I made this wrapping context provider. It should make it easier to copy elements when using multiple sortable containers, or at least provide some easy to use stories to extract from.
@tisdadd I will test it this weekend thank !
@Raphael-Bahuau Thanks much. :-) I changed the data structure before posting to try to make it a bit faster, but found (and fixed) some glitches that I just added to the tests so you may need to redownload - also, it was more aimed at the base problem with the cloning, but I will give some thoughts on the re-rendering as well over the weekend. I am thinking some sort of easy memo for it based on what changed most recently, but not sure how many components it will need on screen before it becomes worth doing that.
Quick update - I did some minor changes to the stories to help a bit with this and added a control to add lots of extra elements to one story. This should help to determine if it is going to need that optimization or not for you.
// SortableCollection
const innards = useMemo(() => {
return items.length > 0
? items.map(({ id: squareId, item, copiedFromId }) => (
<Component
key={squareId}
extraText={typeof item === 'string' ? item : item.extraText}
id={squareId}
value={value}
sortable={true}
dndCopy={dndCopy}
dndMaintainOriginalId={dndMaintainOriginalId}
copiedFromId={copiedFromId}
dndDisallowContainerChanging={dndDisallowContainerChanging}
// simple way to pass down further
itemDataFunction={itemDataFunction}
/>
))
: 'No Items'
}, [items, value?.active?.id])
Using like this keeps the insides of the collection from re-rendering - though most advise for using other memo things appears to be to check if it is an issue before worrying too much - the more nodes, the more likely it is. At some point, depending upon your use case you may have to use a virtualized system of some sort and possibly tweak this sort of setup around that as, for instance, react-window throws off some of the information that this utilizes to properly clone.
Anyway, should there be any issues feel free to raise and I can let you know there if I feel able to address or not.