react-draggable
react-draggable copied to clipboard
update element position automatically when bounds is updated
when bounds changed
For example "bounds" area becomes smaller. Update draggable element position automatically, in case of element getting out of the visible area. Or just trigger the onDrag event once.
@o02112 I have the same problem. Did you find solution for this bug?
@o02112 I have the same problem. Did you find solution for this bug?
Not yet, I just let the element be there where it is, even it out of the visible area.
I've solved this problem by essentially faking a mouse down event. You'll have to decide for yourself when to call this fakeDrag function obviously, but I've included a window resize example. Tested on Chrome 72 and version 3.2.1 of react-draggable.
class SomeReactComponent extends React.Component<Props> {
private childRef: React.RefObject<HTMLDivElement>;
constructor(props) {
super(props);
this.childRef = React.createRef();
}
componentDidMount() {
window.addEventListener('resize', this.onWindowResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this.onWindowResize);
}
render() {
const props = this.props;
return (
<Draggable
axis={"x"}
bounds={"parent"}
>
<div
ref={this.childRef}
>
{props.children}
</div>
</Draggable>
)
}
private onWindowResize = () => {
this.fakeDrag();
};
private fakeDrag = () => {
const clickEvent = document.createEvent ('MouseEvents');
clickEvent.initEvent ("mousedown", true, true);
this.childRef.current.dispatchEvent(clickEvent);
}
}
I wasn't able to get @EitanElbaz's solution to work for me but I made some modifications and now it is working. The key was triggering a mousemove on the document:
onWindowResize = () => {
//trigger a fake drag event here so that the dialog will stay in the window on window resize
const targetNode = document.querySelector(`.${Classes.DIALOG_HEADER}`);
if (targetNode) {
//--- Simulate a natural mouse-click sequence.
triggerMouseEvent(targetNode, "mouseover");
triggerMouseEvent(targetNode, "mousedown");
triggerMouseEvent(document, "mousemove");
triggerMouseEvent(targetNode, "mouseup");
triggerMouseEvent(targetNode, "click");
} else console.log("*** Target node not found!");
function triggerMouseEvent(node, eventType) {
const clickEvent = document.createEvent("MouseEvents");
clickEvent.initEvent(eventType, true, true);
node.dispatchEvent(clickEvent);
}
};
Is there any progress?
Here's a functional component that wraps react-draggable and applies the (second) fix above. You should be able to use it as a drop in replacement for react-draggable.
import { useRef, useEffect } from "react";
import ReactDraggable from "react-draggable";
const Draggable = ({ children, ...props }) => {
const ref = useRef();
useEffect(() => {
const listener = () => {
triggerMouseEvent(ref.current, "mouseover");
triggerMouseEvent(ref.current, "mousedown");
triggerMouseEvent(document, "mousemove");
triggerMouseEvent(ref.current, "mouseup");
triggerMouseEvent(ref.current, "click");
};
addEventListener("resize", listener);
return () => removeEventListener("resize", listener);
}, []);
const triggerMouseEvent = (element, eventType) => {
const mouseEvent = document.createEvent("MouseEvents");
mouseEvent.initEvent(eventType, true, true);
element.dispatchEvent(mouseEvent);
};
return (
<ReactDraggable {...props}>
<div style={{ display: "inline-block" }} ref={ref}>
{children}
</div>
</ReactDraggable>
)
};
export default Draggable;
For some reason, I also needed display: "inline-block" but you might be able to remove that. I hope this helps someone.
I slightly modified @tuzz's solution to move away from deprecated Event.initEvent:
// ...
const triggerMouseEvent = (element, eventType) => {
const mouseEvent = new Event(eventType, {
bubbles: true,
cancelable: true,
});
element.dispatchEvent(mouseEvent);
};
// ...