Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion: drop decisions #1239

Open
alexreardon opened this issue Apr 10, 2019 · 4 comments
Open

Discussion: drop decisions #1239

alexreardon opened this issue Apr 10, 2019 · 4 comments

Comments

@alexreardon
Copy link
Collaborator

Right now we control what can be dropped over using Droppable type and isDropEnabled. A disabled Droppable is not informed if it is being dragged over.

Sometimes it is useful to know when a user is over a disabled droppable.

Option: change isDropDisabled behaviour

Update the onDragUpdate => DragUpdate, Droppable => DroppableStateSnapshot and Draggable => DraggableStateSnapshot to include disabled Droppables?

  • You would still not be able to move to the disabled area with a keyboard
  • No reordering would occur in the disabled list (might be a bit strange to communicate in the state snapshots)

Option: add shouldDrop callback

Rather than relying on isDragDisabled a consumer could use a separate callback shouldDrop (or similar name) to decide whether a drop should be allowed after a user has indicated that a drop should end (such as my a mouseup event)

type ShouldDropFn = (result: DropResult) => boolean

Other?

My thinking on this is not super thorough. Other ideas would be appreciated!

@gvinokur
Copy link

Hi @alexreardon,
Been using the library for the last few days and seems super straightforward to implement.
One issue I am having some problems with is to handle custom drag & drop rules (disabling dragging/dropping over certain positions depending on some business rules).
Having this functionality would allow this implementation to happen, as you can mark the droppable as as disabled while dragging over an invalid position, and reenable it when it's on a valid position.
Another good use case of this would be to be able to add invalid markers to disabled drop zones based on dragging elements to give more clarity to end users why some actions are not achievable.
I have not looked into the implementation details of the library, but I imagine that this functionality may incur on performance issues, I would make it conditional and disable it by default if that's the case.

To conclude:
I made an abstraction that includes the 2 following functions:
canDrag(source) => Rather simple and hooks into the draggable isDraggableDisabled
canDropIn(source, destination) => Complicated:
-- Ideally disables the drop while returning false, now implementing custom indication that drop won't be triggered (changes done at the droppable and draggable styles)
-- Intercepts the call of onDragEnd of the DragDropContext and only calls the underlying method if returns true.

I hope this helps.
Thanks for all your work!

@holmberd
Copy link

holmberd commented May 13, 2020

Having a isDropDisabled prop would definitely make it easier to handle dragging a selected item in a multi-drag situation.

There are also more cases were having conditional drop conditions would be helpful.

@jchamb
Copy link

jchamb commented Mar 4, 2021

+1 for having drop decisions for invalid positions. I've had a a few use cases where to keep list performance with windowing and grouped lists I've needed to create flattened lists to virtualize all items at a single level including header/footer.

I've hacked together some drop logic that shifts index's to stick items above/below, but it would be nice to represent this directly during the drag where specific indexes/index-ranges wouldn't get the translated spacing downward.

@dimbslmh
Copy link

dimbslmh commented Sep 30, 2022

If you want to use isDropDisabled for drop decisions, you would need to pass your restrictions and the DragStart to the <Droppable /> and then determine if the isDropDisabled should be true or not.

E.g. if you have a limit restriction for <Draggable /> components allowed in a <Droppable /> and want to still be able to reorder them you can do the following:

  export default function ElementList({
    droppableId,
    elementMap,
    limit,
    dragStart,
  }) {
    const [isDroppable, setIsDroppable] = useState(true);
    const list = elementMap[droppableId];
  
    useEffect(() => {
      if (dragStart) {
        const isSelf = dragStart.source.droppableId === droppableId;
        const isLimitReached = list.length === limit;
  
        if (isLimitReached && !isSelf) {
          if (isDroppable) setIsDroppable(false);
        }
      } else {
        if (!isDroppable) setIsDroppable(true);
      }
    }, [dragStart]);
  
    const isDropDisabled = !isDroppable;
  
    return (
        <Droppable droppableId={droppableId} isDropDisabled={isDropDisabled}>
        {provided => {
            return (
              <div
                ref={provided.innerRef}
                {...provided.droppableProps}
              >
                {provided.placeholder}
              </div>
            );
        }}
        </Droppable>
    );
  }

This way you can add multiple restrictions, e.g. a whitelist to determine if the dragStart.draggableId should be allowed in the <Droppable /> or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants