-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
transform on parent messes up dragging positioning #128
Comments
Check out the 'Warning: position: fixed' section under |
Thanks for raising this @nickaversano !! |
@alexreardon what about having an option to use pure position fixed positioning? In this mode, the position of the placeholder would be set entirely by |
Interesting idea @nickaversano - worth thinking about. Generally updating top/left values during a drag is not ideal as it does not use the GPU. However, it may get around the issue. We are trying to keep the API as clean as possible so adding an option might not be ideal. In the mean time, you could achieve this yourself! Here is the type for the draggable style: export type DraggingStyle = {|
// Allow scrolling of the element behind the dragging element
pointerEvents: 'none',
// `position: fixed` is used to ensure that the element is always positioned
// in the correct position and ignores the surrounding position:relative parents
position: 'fixed',
// When we do `position: fixed` the element looses its normal dimensions,
// especially if using flexbox. We set the width and height manually to
// ensure the element has the same dimensions as before it started dragging
width: number,
height: number,
// When we set the width and height they include the padding on the element.
// We use box-sizing: border-box to ensure that the width and height are inclusive of the padding
boxSizing: 'border-box',
// We initially position the element in the same visual spot as when it started.
// To do this we give the element the top / left position with the margins considered
top: number,
left: number,
// We clear any top or left margins on the element to ensure it does not push
// the element positioned with the top/left position.
// We also clear the margin right / bottom. This has no positioning impact,
// but it is cleanest to just remove all the margins rather than only the top and left.
margin: 0,
// Move the element in response to a user dragging
transform: ?string,
// When dragging or dropping we control the z-index to ensure that
// the layering is correct
zIndex: ZIndex,
|} You could set the transform to Here is the format of the transform: `translate(${point.x}px, ${point.y}px)` |
Let me know how you go |
I think for now I'm just going to remove the |
Even better! |
I managed to get this to work with Portal from react-dom without changing styles etc. I added a dom element into my html
Added the following styles
And then added this to the Draggable
Hope this helps :) |
Sorry if i'm not supposed to post in closed issues, but i figured this might help if someone else is still having the same problem. I had the same issue when moving an item from a nested list to the parent list, due to the nested lists' container getting transformed when it is "moved down" to show where the dragged item will drop. I finally managed to make a CSS based workaround and thought I should share it incase someone else still has the same problem. My solution was to monitor the parent containers styles and when it gets a transform, i recalculate the inner items transform to compensate with the formula
|
there isn't an official solution for now, right ? |
Budy you saved my life many thankful to you |
This mostly worked for me.. Or, at least, now when I do the drag things align. However when I drop the animation zooms back to the position it would have been in without the transform. Is there a way that I can adjust the drop animation start position? |
if you just want to change position:fixed property you don't have to use portal. You can do override. If you don't know how you can do i can look my old project for you. Portal will isolate parent css from child DOM element. |
Ah. I didn't think of adjusting the position in the style element. Thank you |
I found that although this fixed the dragging offset, when I drop the item the animation is from where the original position would have been |
@zachsa This is my project, i think this can be helpful to you. |
thank you - that does look like it's exactly what i want to do. Before I start looking through the source (still quite difficult for me), would you mind if I just double check with you that I'm on the right track?
It looks like this is something that your code will fix! I'll give it a go - please let me know if I'm NOT on the correct track !! |
Firstly sorry for my complicated code. I think yes you are in correct track. If you wish you can share your project, maybe i can help to you better. |
I've reopening this as there is still discussion going. I will try to get to it soon |
This almost works form me, it fixes dragging positioning issue but all the other cards disappears, I just need to tweak this a little more. |
Worked for me but I have changed this piece to work fine: const x =
parseFloat(childValues[1], 10) -
parseFloat(
provided.draggableProps.style.left,
10,
)
const y =
parseFloat(childValues[2], 10) -
parseFloat(
provided.draggableProps.style.top,
10,
) And this one too: style={{
...provided.draggableProps.style,
transform,
position: snapshot.isDragging
? 'absolute'
: '',
}} |
@kasperpihl where I can buy beer for you? You saved my day. |
That is super exhilarating to hear @borisowsky, @kasperpihl, I tried implementing a solution in codesandbox here: https://codesandbox.io/s/react-beautiful-dnd-h4lk7?file=/src/index.js In this example, I translate the drag and drop list by 30 in the x and y direction, however, even after using portals, the dragging behavior is offset. Any help/ a working example on code sandbox would be amazing, thank you! |
Thank you for your share. I have a question here how can I get/set |
I had the same issue. Following the great solution of @kasperpihl, I created a simple hook do do the trick: Hook:const useDraggableInPortal = () => {
const self = useRef({}).current;
useEffect(() => {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.pointerEvents = 'none';
div.style.top = '0';
div.style.width = '100%';
div.style.height = '100%';
self.elt = div;
document.body.appendChild(div);
return () => {
document.body.removeChild(div);
};
}, [self]);
return (render) => (provided, ...args) => {
const element = render(provided, ...args);
if (provided.draggableProps.style.position === 'fixed') {
return createPortal(element, self.elt);
}
return element;
};
}; Usage:Considering the following component: const MyComponent = (props) => {
return (
<DragDropContext onDragEnd={/* ... */}>
<Droppable droppableId="droppable">
{({ innerRef, droppableProps, placeholder }) => (
<div ref={innerRef} {...droppableProps}>
{props.items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{item.title}
</div>
)}
</Draggable>
)}
{placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}; Just call the hook and use the returned function to wrap the children callback of const MyComponent = (props) => {
+ const renderDraggable = useDraggableInPortal();
return (
<DragDropContext onDragEnd={/* ... */}>
<Droppable droppableId="droppable">
{({ innerRef, droppableProps, placeholder }) => (
<div ref={innerRef} {...droppableProps}>
{props.items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
+ {renderDraggable((provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{item.title}
</div>
))}
</Draggable>
+ ))}
{placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}; Hope it'll help. |
> {optionalPortal(provided.draggableProps.style, (
This works great, but just use: |
I face the same out-of-position problem. When I try to implement it like @daljeetv I get an error Do you guys have any ideas what the reason could be? |
Anyone who has still this problem I made a repository where I made an example for it and in the README you can also find a more simple solution. I found it from here in a comment and it works fine. Note: I had another problem where the dragged div was disappear and I found out it was because of z-index and it dropped behind the parent div. So if e.g. you have a sidebar and its z-index is 999 you have to set the div of Draggable component above that (e.g. z-index: 1000;). Here is my repo: https://github.com/DucktorDanny/react-beautiful-dnd-example I hope I could help. :) |
Hey Danny, thank you so much!
Holen Sie sich Outlook für Android<https://aka.ms/ghei36>
…________________________________
From: ducktor <[email protected]>
Sent: Sunday, January 31, 2021 7:35:36 PM
To: atlassian/react-beautiful-dnd <[email protected]>
Cc: Maxeeezy <[email protected]>; Comment <[email protected]>
Subject: Re: [atlassian/react-beautiful-dnd] transform on parent messes up dragging positioning (#128)
Anyone who has still this problem I made a repository where I made an example for it and in the README you can also find a more simple solution. I found it from here in a comment and it works fine.
Note: I had another problem where the dragged div was disappear and I found out it was because of z-index and it dropped behind the parent div. So if e.g. you have a sidebar and its z-index is 999 you have to set the div of Draggable component above that (e.g. z-index: 1000;).
Here is my repo: https://github.com/DucktorDanny/react-beautiful-dnd-example
I hope I could help. :)
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub<#128 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AKDBV6LFZ4KCZCQFD2NMZ73S4WPHRANCNFSM4D5IE6IA>.
|
@duktorD @maxeezy - you could even do something as simple as:
it would only work as long as your component doesn't re-render during the drag i think |
For React TypeScript, the hook will look like : import { DraggableProvided, DraggingStyle } from 'react-beautiful-dnd'
import { ReactElement, useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
export const useDraggableInPortal = () => {
const element = useRef<HTMLDivElement>(document.createElement('div')).current
useEffect(() => {
if (element) {
element.style.pointerEvents = 'none'
element.style.position = 'absolute'
element.style.height = '100%'
element.style.width = '100%'
element.style.top = '0'
document.body.appendChild(element)
return () => {
document.body.removeChild(element)
}
}
}, [element])
return (render: (provided: DraggableProvided) => ReactElement) => (provided: DraggableProvided) => {
const result = render(provided)
const style = provided.draggableProps.style as DraggingStyle
if (style.position === 'fixed') {
return createPortal(result, element)
}
return result
}
} |
@renaudtertrais thanks so much bro!!! Congratulations! This works for me. |
Maybe it will help someone. I also had problems with positioning when dragging. I had the "fixed" and "transform" styles on the sidebar, but the problem was a different "will-change: transform" style. Everything worked without this style. My versions of the packages "react-beautiful-dnd": "13.1.0" and "@storybook/react": "6.5.9". |
I can't see anyone mentioning this yet, but there is actually some official documentation on how to deal with
The solution seems to be to use the |
I wonder why even |
I was having the same issue while doing an animation as the component mounted and my fix was to simply remove the transform property after the animation was done. Use
I removed whole style attribute because it was a div only used for the transition. |
@kasperpihl 's portal solution helped me a lot. import { merge } from 'lodash';
import cls from './style.module.scss';
const MyComponent = (props) => {
const viewportRef = useRef(null); // find the 'transform parent'
return (<div ref={viewportRef} style={{ transform: 'translateX(0)' }}>
<DragDropContext onDragEnd={/* ... */}>
{/* ... */}
{props.items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided, { isDragging }) => (
<div
{/* ... */}
className={cls.item}
style={merge(
provided.draggableProps.style,
/** relative position item to window - relative position parent to window = relative position item to parent */
isDragging ? {
left: provided.draggableProps.style.left - viewportRef.current.getBoundingClientRect().left,
top: provided.draggableProps.style.top - viewportRef.current.getBoundingClientRect().top,
} : {}
)}
>
{item.title}
</div>
)}
</Draggable>
))}
{/* ... */}
</DragDropContext>
<div>);
}; |
Has anyone had any luck if the parent is scaled instead of just shifted? |
same issue.... |
So the fix that will work for everybody is to use renderClone as described https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/guides/reparenting.md and ya'll are good to go. |
404 |
https://github.com/atlassian/react-beautiful-dnd/blob/HEAD/docs/guides/reparenting.md |
Bug
Expected behaviour
Dragging an item maintains the proper positioning.
Actual behaviour
The item is pushed down by the height of the neighboring element.
Steps to reproduce
Create the following html structure:
Such that react beautiful dnd is monted as a sibling of an element with some height. The parent of the dnd component should have some transform property as well.
Browser version
Google Chrome: Version 61.0.3163.100 (Official Build) (64-bit)
Demo
https://www.webpackbin.com/bins/-KvOoCqQRkMYJzq63hlS
video: https://user-images.githubusercontent.com/5448363/166853462-519f2b79-43de-43b8-8912-6d84a71a1847.mov
react-beautiful-dnd-bug.mov
The text was updated successfully, but these errors were encountered: