react-beautiful-dnd
react-beautiful-dnd copied to clipboard
support lockaxis feature
Hello guys,
I know a ticket for this has already been opened and closed because for now support for lock axis isn't part of the atlassian use case but it may be a use case of different people (such as my case for example) which prevents me from using this framework making me have to switch to an inferior one.
Would you pretty please consider adding lock axis support?
I'm sure there are other people that ended up not using this framework because of that.
Thank you for your time.
From the docs:
Application 5: no drag axis locking
For now, the library does not support drag axis locking (aka drag rails). This is where the user is restricted to only dragging along one axis. The current thinking is this breaks the physical metaphor we are going for and sends a message to the user that they are interacting with a piece of software rather than moving physical objects around. It is possible to ensure that a user can only drop in a single list by using props type and isDropDisabled. You can also do some visual treatment to the list onDragStart to show the user that this is the only place they can interact with.
Any update on this? Would love to see a lock axis feature soon
See https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/about/design-principles.md#application-5-no-drag-axis-locking
That said, you could try to hack it by patching the transform
in the DraggableStyle
It looks like a lot of people want this. I'm open to talking about it more
The current thinking is this breaks the physical metaphor we are going for and sends a message to the user that they are interacting with a piece of software rather than moving physical objects around
Organizing things on a rail can be physical, like Apple's date picker.
It's not exactly drag-and-drop, but it is a physical UI and it shows rails can have a useful aesthetic purpose.
My use case for locked-axis draggables is slides in a presentation. There's a reordering animation there that is really pleasant, but when a user moves the draggable out of the slide list it clips under the presentation and gives the user the impression that they can do something more with it by moving it somewhere in the UI.
That said, you could try to hack it by patching the
transform
in theDraggableStyle
This only partially works... The draggable follows the cursor on one axis fine, but if the draggable moves too far in the locked direction and its width is too small, the gap for dropping closes (even though the draggable's UI is still in the list). Hacks are hacks, and this one only really works when your draggables are large enough.
It works for the slide reordering fine, because our slide cards are fairly large and there's no chance of that confusing animation happening. But for others this this may not work as well, and there's most definitely more reasons than the one I gave.
This could cause usability problems, for example interaction with other droppable parents. Movement from one board to the other wouldn't be possible when the axis is locked. I don't think this is inherently a bad thing, because the most common case for "locked axis" is a 1-Dimensional list.
@alexreardon If you are open to supporting something like this, would you consider jalkoby's PR or Benjaki2's fork to be possible accepted solutions to this issue?
Thanks for reading!
Still waiting for axis locks...
That said, you could try to hack it by patching the
transform
in theDraggableStyle
Here's how I've y-axis locked my verticle list, so the Draggable's can only be dragged up and down, by overriding the transform when dragging for the x-asis.
function getStyle(style, snapshot) {
if (style.transform) {
const axisLockY =
"translate(0px" +
style.transform.slice(
style.transform.indexOf(","),
style.transform.length
);
return {
...style,
transform: axisLockY
};
}
return style;
}
And adding the style to the child of the Draggable component using the draggable props:
style={getStyle(
draggableProvided.draggableProps.style,
draggableSnapshot
)}
nice solution
function getStyle(style, snapshot) { if (style.transform) { const axisLockY = "translate(0px" + style.transform.slice( style.transform.indexOf(","), style.transform.length ); return { ...style, transform: axisLockY }; } return style; }
And adding the style to the child of the Draggable component using the draggable props: ```js style={getStyle( draggableProvided.draggableProps.style, draggableSnapshot )}
and you can simplify it to
function getStyle(style, snapshot) { return { ...style,style.transform ? 'translate(0px',+style.transform.split(',')[1] : null, }; }
Still waiting for axis locks...
It will never happen.
On Wed, Nov 4, 2020, 02:51 zhongzhong [email protected] wrote:
Still waiting for axis locks...
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/atlassian/react-beautiful-dnd/issues/538#issuecomment-721482308, or unsubscribe https://github.com/notifications/unsubscribe-auth/AD7WGR5XFE24OQH2FQ2FQ3DSOC6TXANCNFSM4FC4EKNQ .
well I havent been here a while :p
Might as well ask: is this a feasible thing to do using plain on Drag and Drop API from the browser? how would you block the dragged item from moving past the container?
nice solution
function getStyle(style, snapshot) { if (style.transform) { const axisLockY = "translate(0px" + style.transform.slice( style.transform.indexOf(","), style.transform.length ); return { ...style, transform: axisLockY }; } return style; }
And adding the style to the child of the Draggable component using the draggable props: ```js style={getStyle( draggableProvided.draggableProps.style, draggableSnapshot )}
and you can simplify it to
function getStyle(style, snapshot) { return { ...style,style.transform ? 'translate(0px',+style.transform.split(',')[1] : null, }; }
you can still simplify)
function getStyle(style) {
if (style?.transform) {
const axisLockY = `translate(0px, ${style.transform.split(',').pop()}`;
return {
...style,
transform: axisLockY,
};
}
return style;
}
So if you want to block the X axis:
const draggingCustomStyle = (style: React.CSSProperties | undefined) => {
if (style?.transform) {
const axisLockX = `${style.transform.split(",").shift()}, 0px)`;
return {
...style,
transform: axisLockX,
};
}
return style;
};
I think I see why this hasn't been implemented, the transform property is generated in src/animation.js
, it's a fair few steps - however it would be nice if properties could be passed down via getStyle()
->getDraggingStyle()
& getSecondaryStyle()
-> transforms.moveTo()
.
It would be nice to also have a maximum deviation. I understand that it's nice having a free flowing draggable but it's also useful to tell the user this stays here, so for instance it could be set to only allow y
axis but allows 20px movement on the x axis.
I'll make a PR with these changes.
edit: Also a slight problem that I noticed, if axis limiting is used to seperate droppable areas keyboards can still move them. It was something I noticed with other people's "solutions", they forgot about keyboard controls.
nice solution
function getStyle(style, snapshot) { if (style.transform) { const axisLockY = "translate(0px" + style.transform.slice( style.transform.indexOf(","), style.transform.length ); return { ...style, transform: axisLockY }; } return style; }
And adding the style to the child of the Draggable component using the draggable props: ```js style={getStyle( draggableProvided.draggableProps.style, draggableSnapshot )}
and you can simplify it to
function getStyle(style, snapshot) { return { ...style,style.transform ? 'translate(0px',+style.transform.split(',')[1] : null, }; }
you can still simplify)
function getStyle(style) { if (style?.transform) { const axisLockY = `translate(0px, ${style.transform.split(',').pop()}`; return { ...style, transform: axisLockY, }; } return style; }
🥰Thank you so much
@Halimazeez , it's nice solution but it has problem for the mouse pointer. If the mouse pointer is out of droppable area, the placeholder area is removed. In the screenshot below, mouse pointer is out of droppable area.
The transform is returned as an object in newer version. It can be done even simpler:
const { attributes, isDragging, listeners, setNodeRef, transform, transition } = useSortable({ id });
const style = {
transform: transform && isDragging ? CSS.Transform.toString({ ...transform, x: 0 }) : CSS.Transform.toString(transform),
transition,
};
My variation on this. Works like a charm as long as the width of the wrapper component is the same as the draggable items.
import { Draggable } from 'react-beautiful-dnd';
function getStyle(style) {
if (style?.transform) {
const axisLockY = `translate(0px, ${style.transform.split(',').pop()}`;
return {
...style,
transform: axisLockY,
};
}
return style;
}
style={getStyle({ ...provided.draggableProps.style, ...provided.draggableSnapshot })}
function getStyle(style) { if (style?.transform) { const axisLockY =
translate(0px, ${style.transform.split(',').pop()}
; return { ...style, transform: axisLockY, }; } return style; }
works thanks a lot
Concise solutions for both horizontal and vertical.
export const getStyleHorizontalLock = style => style?.transform
? ({ ...style, transform: `translate(${style.transform.split(',')[0].split('(').pop()}, 0px)` })
: style
export const getStyleVerticalLock = style => style?.transform
? ({ ...style, transform: `translate(0px, ${style.transform.split(',').pop()}` })
: style
The usage is the same as the other solutions provided by @chervyakovru etc