Skip to content

Commit 011e8a7

Browse files
author
Amrit Kashyap Borah
committed
fix: bound movement of draggable to screen
1 parent b840f07 commit 011e8a7

1 file changed

Lines changed: 23 additions & 43 deletions

File tree

src/Common/DraggableWrapper/DraggableWrapper.tsx

Lines changed: 23 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,9 @@ export default function DraggableWrapper({
3838
}: DraggableWrapperProps) {
3939
const windowSize = useWindowSize()
4040
const nodeRef = useRef<HTMLDivElement>(null)
41-
42-
const [position, setPosition] = useState<ControlPosition>({
43-
x: 0,
44-
y: 0,
45-
})
41+
42+
// letting the dom render the element without displaying it so that we know it's dimensions
43+
const [initialRenderDone, setInitialRenderDone] = useState(false)
4644

4745
const getDefaultPosition = (positionVariant: DraggablePositionVariant): ControlPosition => {
4846
// if this return x: 0, y: 0 then it will be top left corner of parentDiv
@@ -60,73 +58,55 @@ export default function DraggableWrapper({
6058

6159
switch (positionVariant) {
6260
case DraggablePositionVariant.PARENT_BOTTOM_CENTER: {
63-
// currently at parentRect.x and need to start to the center of its width and half of node should lie on left of center and other half on right
64-
const x = (parentRect.width - nodeRefWidth) / 2
61+
// center div to middle of the parent rect and then add the left offset of the parent rect
62+
const x = (parentRect.width - nodeRefWidth) / 2 + parentRect.left
6563
// TODO (v3): Temp fix. Revisit
6664
const parentRectTop = parentRect.top > 0 ? parentRect.top : layoutFixDelta
6765
// currently at parentRect.y now parent height can be greater than windowSize.height so taking min
6866
// subtracting parentRect.top since window height already contains that
69-
const baseY =
70-
parentRect.height > windowSize.height ? windowSize.height - parentRectTop : parentRect.height
71-
const y = baseY - nodeRefHeight - boundaryGap
67+
if (parentRect.height > windowSize.height) {
68+
return { x, y: windowSize.height - boundaryGap - nodeRefHeight }
69+
}
70+
const y = parentRect.bottom - nodeRefHeight - boundaryGap
7271
return { x, y }
7372
}
7473
case DraggablePositionVariant.SCREEN_BOTTOM_RIGHT: {
75-
const x = windowSize.width - parentRect.left - nodeRefWidth - boundaryGap
76-
const y = windowSize.height - parentRect.top - nodeRefHeight - boundaryGap
74+
const x = windowSize.width - nodeRefWidth - boundaryGap
75+
const y = windowSize.height - nodeRefHeight - boundaryGap
7776

7877
return { x, y }
7978
}
8079
// Add more cases for other variants if needed
8180
default: {
8281
// Since need node to be in center of screen so subtracting width/2 by left of parentRect it will start the node from center but want node's midpoint at center so subtracting node's width from it.
83-
const x = windowSize.width / 2 - parentRect.left - nodeRefWidth / 2
82+
const x = (windowSize.width - nodeRefWidth) / 2
8483
// subtracting top since windowSize already contains that
85-
const y = windowSize.height - parentRect.top - nodeRefHeight - boundaryGap
84+
const y = windowSize.height - nodeRefHeight - boundaryGap
8685

8786
return { x, y }
8887
}
8988
}
9089
}
9190

92-
// On change of windowSize we will reset the position to default
9391
useEffect(() => {
94-
const defaultPosition = getDefaultPosition(positionVariant)
95-
setPosition(defaultPosition)
96-
}, [nodeRef, positionVariant, windowSize])
97-
98-
// Would be called on drag and will not update the state if the new position is out of window screen
99-
function handlePositionChange(e, data: DraggableData) {
100-
const offsetX = parentRef?.current?.getBoundingClientRect().left ?? 0
101-
const offsetY = parentRef?.current?.getBoundingClientRect().top ?? 0
102-
103-
const nodeRefHeight = nodeRef.current?.getBoundingClientRect().height ?? 0
104-
const nodeRefWidth = nodeRef.current?.getBoundingClientRect().width ?? 0
105-
106-
if (
107-
offsetX + data.x + nodeRefWidth + boundaryGap > windowSize.width ||
108-
offsetY + data.y + nodeRefHeight + boundaryGap > windowSize.height ||
109-
offsetX + data.x < 0 ||
110-
offsetY + data.y < 0
111-
) {
112-
return
113-
}
114-
115-
setPosition({
116-
x: data.x,
117-
y: data.y,
118-
})
119-
}
92+
// make the element visible after the initial render
93+
setInitialRenderDone(true)
94+
}, [])
12095

12196
return (
12297
// Since we are using position fixed so we need to disable click on the div so that it does not interfere with the click of other elements
12398
<div
124-
className="dc__position-fixed dc__disable-click"
99+
className={`dc__position-fixed dc__disable-click dc__top-0 dc__left-0 ${initialRenderDone ? '' : 'dc__visibility-hidden'}`}
125100
style={{
126101
zIndex,
127102
}}
128103
>
129-
<Draggable handle={dragSelector} nodeRef={nodeRef} position={position} onDrag={handlePositionChange}>
104+
<Draggable
105+
key={`${JSON.stringify(windowSize)} ${initialRenderDone}`}
106+
handle={dragSelector}
107+
defaultPosition={getDefaultPosition(positionVariant)}
108+
bounds="#devtron-base-main-identifier"
109+
nodeRef={nodeRef}>
130110
<div
131111
ref={nodeRef}
132112
{...childDivProps}

0 commit comments

Comments
 (0)