atlassian / react-beautiful-dnd

Beautiful and accessible drag and drop for lists with React
https://react-beautiful-dnd.netlify.app
Other
33.24k stars 2.53k forks source link

Support dragging a copy (leave original in place) #216

Open rogerjak opened 6 years ago

rogerjak commented 6 years ago

Is it possible to keep the dragged source in the list and instead drop a copy of it? I have four lists/columns: | Available objects | When | And | Then | and I need the items in the first column to always be there.

alexreardon commented 6 years ago

At this time we are not supporting a copy drag. This goes against the physicality this library is aiming for

alexreardon commented 6 years ago

Thanks for reaching out! Perhaps this suggestion would be useful to you: https://github.com/atlassian/react-beautiful-dnd/issues/155

Geczy commented 6 years ago

I have the same requirement, are you sure this isn't possible?

221

rogerjak commented 6 years ago

@Geczy I moved on to react-sortable, after some hacking I got what I wanted. Granted; not as nice as beautiful-dnd would be...

HenrikBechmann commented 6 years ago

Damn. Not supporting copy is a showstopper for me.

alexmcmanus commented 6 years ago

It's not that hard to implement clone/copy already. In your source Droppable, set isDropDisabled={true}. This stops the source re-ordering when you drag an item - but it will leave a blank space behind when you start dragging. To avoid the blank space, in your Draggable, customize the rendering of the placeholder. If placeholder is not null, render whatever you'd like left behind, at the same width and height as the original. E.g. { provided.placeholder ? (this.renderMyOwnPlaceholder()) : null }.

Then, you just need to make sure in your endDrag() that you don't remove the item from the source collection.

The only caveat is that the custom placeholder part will probably stop working when the library is upgraded to React 16, as there are numerous mentions in the docs of plans for the explicit placeholder to go away. @alexreardon, it would be great if the updated library were to provide a hook for rendering the placeholder to support this kind of customization.

alexreardon commented 6 years ago

I will take a look into it as we update for react 16. But as mentioned it does go against the physicality we are going for. It is not confirmed how we will do placeholders yet so you might be able to get away with your current approach anyway On Fri, 23 Mar 2018 at 9:30 pm, alexmcmanus notifications@github.com wrote:

It's not that hard to implement clone/copy already. In your source Droppable, set isDropDisabled={true}. This stops the source re-ordering when you drag an item - but it will leave a blank space behind when you start dragging. To avoid the blank space, in your Draggable, customize the rendering of the placeholder. If placeholder is not null, render whatever you'd like left behind, at the same width and height as the original. E.g. { provided.placeholder ? (this.renderMyOwnPlaceholder()) : null }.

Then, you just need to make sure in your endDrag() that you don't remove the item from the source collection.

The only caveat is that the custom placeholder part will probably stop working when the library is upgraded to React 16, as there are numerous mentions in the docs of plans for the explicit placeholder to go away. @alexreadon, it would be great if the updated library were to provide a hook for rendering the placeholder to support this kind of customization.

— You are receiving this because you modified the open/close state.

Reply to this email directly, view it on GitHub https://github.com/atlassian/react-beautiful-dnd/issues/216#issuecomment-375610716, or mute the thread https://github.com/notifications/unsubscribe-auth/ACFN7eb5FbDRWBZdXK-rrSWjLx5MQO1Mks5thM64gaJpZM4Q0kPd .

pchr-srf commented 6 years ago

Regarding the physicality: Maybe the "cloning" could be regarded as an infinite pile of the same item? :)

t1mmen commented 6 years ago

We are considering react-beautiful-dnd as react-dnd replacement, but no copy would be a showstopper for us.

@alexreardon Is this still feature request something you're considering? Does the workaround outlined here work still?

PS: Demos & docs make react-beautiful-dnd look exceptionally well done 👏

rivneglee commented 6 years ago

I have same requirement for copy drag because I need to implement a toolbox component.

jerryliu commented 6 years ago

I have same requirement for clone drag

dvirben123 commented 6 years ago

@rivneglee did you find something for implement your toolbox component?

alexreardon commented 6 years ago

I am happy to think a little bit more about this one. But for now it is fairly low priority

yingchangwu commented 6 years ago

I updated two files and it works pretty good so far. render a copy of the draggable item when isDragging is true, and this will leave a palceholder space, so I updated the placeholder file to hide the placeholder if you pass variable isCopy = true. you can see an working example from https://hungry-curran-3f8f19.netlify.com under single vertial list -> copy clone

circlingthesun commented 6 years ago

This would be quite useful in form builders where you drag new elements onto a page.

vrsttl commented 6 years ago

I understand how the physicality of the idea would be damaged, still, I think this would be a reasonable addition. Edit: anyway, I would imagine a copy function's physicality as getting cookie dough on your fingers and pulling it out of the batch. I think if you guys implemented something like this, the programmers of the world would relate and rejoice :)

Aarbel commented 6 years ago

could be great to put a higher priority on this feature proposition ;)

TrySound commented 6 years ago

One more request for some kind of dnd builders.

pixelass commented 6 years ago

+1 for this feature.

Here's an idea for a more or less stable workaround: (use case: dnd builders)

Code sandbox example

(cloned from https://codesandbox.io/s/ql08j35j3q via https://github.com/atlassian/react-beautiful-dnd#basic-usage-examples)

const Clone = styled(Item)`

This idea should pretty much solve the problem without any hard mutations and enough flexibility to build something that can easily be refactored when the feature gets implemented into core.

dnd4

Since the suggestions with using{snapshot.placeholder && SOMETHING} don't work (placeholder is always null unless a new item is added (moved) to the list, which is not the case if dropping is disabled or elements are reordered), I looked around and stumbled upon the following comment several times: https://github.com/atlassian/react-beautiful-dnd/issues/155#issuecomment-340712628. It took me a while to realize that the answer was hidden within. 🎉 This video helped a lot to understand blocking drags and drops: https://egghead.io/lessons/react-conditionally-allow-movement-using-react-beautiful-dnd-draggable-and-droppable-props

NunoCardoso commented 6 years ago

Very cool, pixelass, I was looking for a solutioin like that. I still have a problem, when I drop into the target area, the animatiom is still a retreat to the source area. Any idea why this happens, and how to fix it?

Edit: it was a problem in my code, it works now. Still, great tip on how to do sticky draggables.

pixelass commented 6 years ago

@NunoCardoso you can render the placeholder as a custom ghost.
This would then animate the target Items correctly.

The source element can be customized but there is no way of knowing the width of the target container unless it's fixed.

A setup like this could help get perfectly smooth transitions.

Here's an earlier prototype of what I',m working on: (you can see there are still issues with the size.)

dnd-ex3

I played around with a toggle mechanism for the items but height is mostly an issue when dragging tall items.
The width issue is on hold since I'm currently creating the entire layout of my app and I hope it will help solve the problems I've had.

instadrew commented 5 years ago

@alexreardon : If this feature were to be implemented, it would also be nice to be able to drag one of the copies back to the starting area as a way of removing it from wherever it had first been dragged, but without the draggables in the starting area moving around. Just a reverse of the drag from the starting area.

faddah commented 5 years ago

+1 for the copy/drag feature — it has precedent in other OS's — Mac OS has long let you copy an item, rather than just move it, in the Finder by holding down the 'option' key while dragging; in Windows, you do the same holding down the 'control' key. would love to see this feature here, also.

kingcanova commented 5 years ago

+1 for the copy/drag feature from me as well, I would love to see this added!

EdmundsEcho commented 5 years ago

I greatly appreciate the design’s conviction to “physicality”.

However, I’m not sure this feature request diverges from what we are already doing.

Given we are able to create a new item... to instantiate something that becomes our physicality, how is this concept to instantiate a new item, different from doing so using a template aka, an already instantiated dnd component.

- E

alexreardon commented 5 years ago

I am more open to this one. A lot of people would find it extremely useful. We would not be looking at it until we finish our Up next milestone

kohenchia commented 5 years ago

This technique no longer works under the latest version (10.x), because they removed snapping. It's a bit hard to explain, but here's an example. All I did was take the example above and update the react-beautiful-dnd version to 10.x:

https://codesandbox.io/embed/1ykz68njw7

In prior versions, this technique relied on the pre-snapped white space to exist as a <div> instantaneously upon dragging, then hiding it with the + div { display: none!important } CSS trick. It also relies on the fact that the pre-snapped whitespace exists up until the very last moment when dragging stops, at which point the CSS display hack also no longer applies.

In the new world where the pre-snapped whitespace is made to shrink in a fluid manner and then disappears, the CSS hack will eventually hide the next item (<div>) down in the list, resulting in one missing item upon dragging. If the CSS hack is removed, this results in janky visualization where the whitespace appears for a short period, pushing down the remaining items, then shifting them back up as the whitespace disappears.

~I don't know what a new workaround would look like, but I would appreciate someone trying to come up with one.~

EDIT: Workaround is to just use 10.0.4 instead of 10.1. Then the @pixelass workaround works perfectly.

pixelass commented 5 years ago

@kohenchia thx for reporting.

Here's a new hack:

const Clone = styled(Item)`
  ~ div {
    transform: none!important;
  }
`;

https://codesandbox.io/s/q3717y1jq4

dnd_new_hack

alexreardon commented 5 years ago

I love the resourcefulness of this thread. I am not committing to shipping copy + drag, but it will be thought about as a part of #68

alexreardon commented 5 years ago

Related: we might need this for #1225

adirzoari commented 5 years ago

@pixelass is there any way to reorder list? in the example on codesandbox it only allow when to "reorder" when there is blank list.. but for example if I insert in one list image and second list text, I want to make the list with the text first and with the image second.. kind of sortable lists

pixelass commented 5 years ago

@adirzoari can you make a screenshot with annotations?

I’ll try to make an example but I currently don’t fully understand the question

adirzoari commented 5 years ago

Screen Shot 2019-04-16 at 19 32 58

this picture I have 2 list. first list 1 include "copy", second 2 include "slideshow". I want to make sortable. list first will be the "2" with slideshow item and the second be "1" with copy item

jimmycarry commented 5 years ago

It doesn't work in 11.0.0 version example :

jimmycarry commented 5 years ago

sorry, see the example

davidosomething commented 5 years ago

@jimmycarry you need to use transform: none !important on the clone's sibling style, not display: none

lauralouiset commented 5 years ago

+1 for copy/clone support! I need this feature, but as I also want touch and keyboard accessibility, react-beautiful-dnd is my first choice of library. It seems a damn shame to have to choose between these two things :-(

alexreardon commented 5 years ago

Perhaps we could revisit this decision if we enabled the ability to disable reordering for a list (but still allowed dragging from the list)

kala888 commented 5 years ago

need it!

beamercola commented 5 years ago

pixelass is my new daddy

Anwardo commented 5 years ago

+1 for copy & clone, it's such a shame this library doesn't support it. Other than this react-beautiful-dnd has everything I need.

lcoder commented 5 years ago

Thanks.Your code helped me! @pixelass

momesana commented 5 years ago

+1 for copy & clone. I would also really appreciate it if the feature finds its way into a future release.

ssjunior commented 5 years ago

+1 for copy & clone

nicubarbaros commented 5 years ago

+1 ^_^

ghost commented 4 years ago

@kohenchia This code is working with me at the latest version.

const Item = styled.div `
   user-select: none;
   border: 1px
   ${props => (props.isDragging ? "dashed #000" : "solid transparent")};
   transform: ${props => !props.isDragging ? "none !important" : ""};
`;
antoine-gmnz commented 4 years ago

I have found a way to simulate the copy function you just need to add {snapshot.isDragging && returnContent(snapshot, true)} returnContent function should have the same return than your component (without the Draggable tag). If you want to make it move with the list your should use snapshot.combineWith in order to know if the dragging element is under or above the placeholder and then set it's position with the CSS property translate(). Not perfect but it worked for me !

ricky-sandoval commented 4 years ago

+1 Copy and clone

demogar commented 4 years ago

I have found a way to simulate the copy function you just need to add {snapshot.isDragging && returnContent(snapshot, true)} returnContent function should have the same return than your component (without the Draggable tag). If you want to make it move with the list your should use snapshot.combineWith in order to know if the dragging element is under or above the placeholder and then set it's position with the CSS property translate(). Not perfect but it worked for me !

@antoine-gmnz can you elaborate more on this?. I notice the combineWith property is always set to null, at least on my current tests.

ghost commented 4 years ago

I have found a way to simulate the copy function you just need to add {snapshot.isDragging && returnContent(snapshot, true)} returnContent function should have the same return than your component (without the Draggable tag). If you want to make it move with the list your should use snapshot.combineWith in order to know if the dragging element is under or above the placeholder and then set it's position with the CSS property translate(). Not perfect but it worked for me !

Same as @demogar . Could you explain alittle more what is suppose to be in the returnContent function?