Trevor DePodesta
Trevor DePodesta

Reputation: 11

How to restrict the draggable area of an element in react-beautiful-dnd

To clarify, I don't mean defining a droppable area, I mean making it so that visually, you literally can't drag items outside of a certain range. For example, if you have a div that houses a bunch of smaller elements and you're currently using react-beautiful-dnd to drag and drop them within the parent div, even though they'll just snap back when you let go you can still visually drag the elements outside of the div--that's what I'd like to avoid.

I made some progress. I want my list items to only be dragged up and down, and modifying the transform style property below did fix that perfectly:

<Draggable key={id} draggableId={id.toString()} index={i}>
    {(provided, snapshot) => {
        var t = provided.draggableProps.style.transform;
        if (t) {
            let y = parseInt(t.split(',')[1].slice(0, -3));
            provided.draggableProps.style.transform = `translate(0px,${y}px)`;
        }

        return (
            <li ref={provided.innerRef} {...provided.draggableProps}>
                <MyCustomElement>
            </li>
        )
    }}
</Draggable>

However, if I add in another line that should theoretically also constrain the y-axis (so that the elements stay within the bounds of the <ul/> parent), is fails:

...
let y = parseInt(t.split(',')[1].slice(0, -3));
y = Math.min(Math.max(y, -(i*60)), 240-(i*60));    // 240 -> container height, 60 -> element height
provided.draggableProps.style.transform = `translate(0px,${y}px)`;
...

The problem is that while this technically does the job of stopping the <li/> element you're dragging from being transformed out of bounds, it's not actually stopping its position as far as the dragging logic is concerned, which makes the other elements freak out.

I promise I tried to look everyone else first on my own for this, but I'm at my wits end on this one.

Upvotes: 1

Views: 1206

Answers (1)

kosiakMD
kosiakMD

Reputation: 1062

to lock horizontal border (area) we used next approach

<Draggable
    key={id}
    draggableId={id}
    index={index}
>
  {(providedDrag) => {
    const transform = providedDrag.draggableProps?.style?.transform;
    if (transform) {
      const t = transform.split(',')[1];
      // eslint-disable-next-line no-param-reassign
      providedDrag.draggableProps.style.transform = `translate(0px,${t}`;
    }
    return(<div
      ref={providedDrag.innerRef}
      /* eslint-disable-next-line react/jsx-props-no-spreading */
      {...providedDrag.draggableProps}
      /* eslint-disable-next-line react/jsx-props-no-spreading */
      {...providedDrag.dragHandleProps}
      key={ticketLevel.id}>
        <div>...</div>
    </div>)
  }
<Draggable/>

to lock vertical area - need to get via Ref Dropable box size and compare with props then override transform

Upvotes: 1

Related Questions