Skip to content

Commit

Permalink
Add movement threshold to prevent unintended moving of an app window
Browse files Browse the repository at this point in the history
  • Loading branch information
devklick committed Oct 18, 2023
1 parent 8a891a3 commit 4c8f182
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 14 deletions.
48 changes: 35 additions & 13 deletions src/hooks/useDragToMove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, {
useRef,
useState,
} from "react";
import { Rect } from "./useDragToResize";
import { Position, Rect } from "./useDragToResize";

// https://stackoverflow.com/a/39192992/6236042

Expand All @@ -19,12 +19,20 @@ interface UseDraggableProps {
moveRef?: React.RefObject<HTMLElement> | null;

elementRect: MutableRefObject<Partial<Rect>>;

threshold?: number;
}

// complex logic should be a hook, not a component
const useDragToMove = ({ moveRef = null, elementRect }: UseDraggableProps) => {
const useDragToMove = ({
moveRef = null,
elementRect,
threshold = 20,
}: UseDraggableProps) => {
const [pressed, setPressed] = useState(false);
const ref = useRef<HTMLElement | null>(null);
const tempRect = useRef<Position>({ x: 0, y: 0 });
const moving = useRef(false);

const unsubscribe = useRef<VoidFunction>();
const moveHandle: RefCallback<HTMLElement> = useCallback((elem) => {
Expand Down Expand Up @@ -52,23 +60,37 @@ const useDragToMove = ({ moveRef = null, elementRect }: UseDraggableProps) => {

const handleMouseMove = throttle(
(event: { movementX: number; movementY: number }) => {
if (!ref.current || !elementRect.current) {
return;
}
const element = moveRef?.current ?? ref.current;

if (!element) return;

elementRect.current.left =
(elementRect.current.left ?? 0) + event.movementX;
tempRect.current.x += event.movementX;
tempRect.current.y += event.movementY;

elementRect.current.top =
(elementRect.current.top ?? 0) + event.movementY;
if (
Math.abs(tempRect.current.x) >= threshold ||
Math.abs(tempRect.current.y) >= threshold ||
moving.current
) {
elementRect.current.left =
(elementRect.current.left ?? 0) + tempRect.current.x;

const elem = moveRef?.current ?? ref.current;
elementRect.current.top =
(elementRect.current.top ?? 0) + tempRect.current.y;

tempRect.current.x = 0;
tempRect.current.y = 0;
moving.current = true;
}

elem.style.left = `${elementRect.current.left}px`;
elem.style.top = `${elementRect.current.top}px`;
element.style.left = `${elementRect.current.left}px`;
element.style.top = `${elementRect.current.top}px`;
}
);
const handleMouseUp = () => {
tempRect.current.x = 0;
tempRect.current.y = 0;
moving.current = false;
setPressed(false);
};
// subscribe to mousemove and mouseup on document, otherwise you
Expand All @@ -84,7 +106,7 @@ const useDragToMove = ({ moveRef = null, elementRect }: UseDraggableProps) => {
// if `onDrag` wasn't defined with `useCallback`, we'd have to
// resubscribe to 2 DOM events here, not to say it would mess
// with `throttle` and reset its internal timer
}, [pressed, moveRef, elementRect]);
}, [pressed, moveRef, elementRect, threshold]);

// actually it makes sense to return an array only when
// you expect that on the caller side all of the fields
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useDragToResize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface Rect extends Dimensions {
left: number;
}

interface Position {
export interface Position {
x: number;
y: number;
}
Expand Down

0 comments on commit 4c8f182

Please sign in to comment.