[BUG] dragConstraints by ref doesn't consider changes after initial render
1. Read the FAQs 👇
2. Describe the bug
If dragConstraints are set by giving a ref of an element, then the size of the draggable element is based off the initial render and not the current size.
3. IMPORTANT: Provide a CodeSandbox reproduction of the bug
https://codesandbox.io/s/framer-motion-drag-constraints-with-changing-size-7ixkj0?file=/src/Example.tsx
4. Steps to reproduce
Steps to reproduce the behavior:
- Go to Sandbox.
- Click on button in top left corner.
- Draggable area for box is the same.
5. Expected behavior
The draggable area should change to accomodate the change in size.
I have just encountered exactly the same issue. I need to scale draggable element and dragConstraints don't reflect that. Is there any workaround in the mean time?
EDIT: For those looking for workaround like me, you can pass number as a key to the draggable component and increase it on draggable component scale. It causes recalculation and constraints work as intended.
Ok since my previous workaround is not so good as I thought and this issue quite troubles me I decided to put my hands on the code a bit.
Version: 10.0.1
Description: When scale is passed in draggable element the constraints behave correctly on initial render but on every consequential rendering the constraints are broken.
Investigation:
resolveRefConstraints method resolves constraints incorrectly
https://github.com/framer/motion/blob/f06854066a1de33561578ce2c4fd785e78fdf3be/packages/framer-motion/src/gestures/drag/VisualElementDragControls.ts#L311
the reason is that projection.layout.layoutBox contains incorrect measurement
https://github.com/framer/motion/blob/f06854066a1de33561578ce2c4fd785e78fdf3be/packages/framer-motion/src/gestures/drag/VisualElementDragControls.ts#L335
it has incorrect measurement because getBoundingClientRect on our draggable instance returns different values than we are expecting
https://github.com/framer/motion/blob/f06854066a1de33561578ce2c4fd785e78fdf3be/packages/framer-motion/src/projection/utils/measure.ts#L14
Why? Compare the following styles on the instance:
initial render
width: 200px; height: 200px; background: white; border-radius: 20px; transform: scale(1.2) translateZ(0px); user-select: none; touch-action: none;
every consequential render
width: 200px; height: 200px; background: white; border-radius: 20px; transform: none; user-select: none; touch-action: none;
So, something somewhere is updating transform property on the element and in time of the measurement the transform is set to value none. Unfortunately I did not manage to locate responsible part of the code. Maybe @mattgperry, could you give me a hand here?
Encountered the same bug, in my case I was changing the initial width of the element. I got to the same conclusion to just pass the width as a key and rerender the component with restraints each time the width changed
I have the same issue. I experimented with updating the dragConstraints based on a window resize of the browser and the dragConstraints sadly don't update when my hook is called.
@mattgperry this issue is different from #2399 .
- the bug still exists in the latest
10.16.7
Updated a sandbox for this issue just for your convenience to confirm it still exists in the latest framer-motion version.
And the following use case would also fail as of 10.16.7:
dragConstraints: !isMoved ? false : { top: 200 },
Has this issue been resolved? Or has anyone found a workaround for this that is reliable?
Would love to know as well.
For me, I'm passing a ref to dragConstraints of a Div which itself is being transformed/animated on scroll. It works fine on desktop, but goes bonkers in iOS.
Same problem here.
Passing to child motion.div dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0, }}
not working even inside a motion.div with initial={{ scale: 0 }} animate={{ scale: 1 }}
pd: unusable, had to implement the drag myself using PointerEvents, but I miss the "elastic" part from motion
Just encountered this, I need a fix for it!