image-converter-client/app/routes/DragableBox.tsx

93 lines
2.3 KiB
TypeScript
Raw Normal View History

2024-11-02 17:25:14 +00:00
import { useState, useEffect, MouseEvent, useRef, Dispatch, SetStateAction } from 'react';
2024-11-03 20:56:34 +00:00
// Todo
// Have selector start at full width and height
// dragable icons rotation
// drag selector
2024-11-02 17:25:14 +00:00
type Coordinates = {
x: number;
y: number;
}
2024-11-02 15:47:17 +00:00
interface DraggableBoxProps {
2024-11-03 17:34:21 +00:00
position: Coordinates;
2024-11-02 15:47:17 +00:00
className?: string;
children?: React.ReactNode;
2024-11-03 17:34:21 +00:00
coordSetter: Dispatch<SetStateAction<Coordinates>>;
2024-11-02 15:47:17 +00:00
}
const DraggableBox = ({
2024-11-03 17:34:21 +00:00
position,
2024-11-02 15:47:17 +00:00
className = "",
2024-11-02 17:25:14 +00:00
children = "",
2024-11-03 17:34:21 +00:00
coordSetter
2024-11-02 15:47:17 +00:00
}: DraggableBoxProps) => {
const [isDragging, setIsDragging] = useState(false);
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
const dragRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!isDragging) return;
const handleMouseMove = (e: globalThis.MouseEvent) => {
if (!dragRef.current?.parentElement) return;
const parent = dragRef.current.parentElement;
const parentRect = parent.getBoundingClientRect();
const relativeX = e.clientX - parentRect.left - dragOffset.x;
const relativeY = e.clientY - parentRect.top - dragOffset.y;
2024-11-03 11:57:42 +00:00
const maxX = parentRect.width;
const maxY = parentRect.height;
2024-11-02 15:47:17 +00:00
2024-11-02 22:30:55 +00:00
let newX = (Math.max(0, Math.min(relativeX, maxX)));
let newY = (Math.max(0, Math.min(relativeY, maxY)));
2024-11-03 17:34:21 +00:00
coordSetter({
x: newX,
y: newY
})
2024-11-02 15:47:17 +00:00
};
const handleMouseUp = () => setIsDragging(false);
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
};
2024-11-03 17:34:21 +00:00
}, [isDragging, dragOffset, position.x, position.y]);
2024-11-02 15:47:17 +00:00
const handleMouseDown = (e: MouseEvent) => {
if (!dragRef.current?.parentElement) return;
const parentRect = dragRef.current.parentElement.getBoundingClientRect();
setDragOffset({
2024-11-03 17:34:21 +00:00
x: e.clientX - parentRect.left - position.x,
y: e.clientY - parentRect.top - position.y
2024-11-02 15:47:17 +00:00
});
setIsDragging(true);
};
return (
<div
ref={dragRef}
2024-11-02 22:30:55 +00:00
className={`absolute cursor-pointer ${className}`}
2024-11-02 15:47:17 +00:00
style={{
2024-11-03 17:34:21 +00:00
transform: `translate(${position.x}px, ${position.y}px)`,
2024-11-02 15:47:17 +00:00
userSelect: 'none',
}}
onMouseDown={handleMouseDown}
>
{children}
</div>
);
};
export default DraggableBox;