image-converter-client/app/routes/DragableBox.tsx
christian 5eab4fd47c
All checks were successful
Deploy to Cloudflare Pages / deploy (push) Successful in 31s
moved state out of url
2024-11-02 18:25:14 +01:00

94 lines
2.6 KiB
TypeScript

import { useState, useEffect, MouseEvent, useRef, Dispatch, SetStateAction } from 'react';
type Coordinates = {
x: number;
y: number;
}
interface DraggableBoxProps {
initialX: number;
initialY: number;
className?: string;
children?: React.ReactNode;
setter?: Dispatch<SetStateAction<Coordinates>>;
}
const DraggableBox = ({
initialX,
initialY,
className = "",
children = "",
setter
}: DraggableBoxProps) => {
const [isDragging, setIsDragging] = useState(false);
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
const [xPosition, setXPosition] = useState(initialX)
const [yPosition, setYPosition] = useState(initialY)
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 boxRect = dragRef.current.getBoundingClientRect();
const relativeX = e.clientX - parentRect.left - dragOffset.x;
const relativeY = e.clientY - parentRect.top - dragOffset.y;
const maxX = parentRect.width - boxRect.width;
const maxY = parentRect.height - boxRect.height;
setXPosition(Math.max(0, Math.min(relativeX, maxX)));
setYPosition(Math.max(0, Math.min(relativeY, maxY)));
if (setter) {
setter({
x: relativeX,
y: relativeY
})
}
};
const handleMouseUp = () => setIsDragging(false);
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
};
}, [isDragging, dragOffset, xPosition, yPosition, initialX, initialY]);
const handleMouseDown = (e: MouseEvent) => {
if (!dragRef.current?.parentElement) return;
const parentRect = dragRef.current.parentElement.getBoundingClientRect();
setDragOffset({
x: e.clientX - parentRect.left - xPosition,
y: e.clientY - parentRect.top - yPosition
});
setIsDragging(true);
};
return (
<div
ref={dragRef}
className={`absolute cursor-move bg-red-500 rounded-full w-4 h-4 text-white shadow-lg ${className}`}
style={{
transform: `translate(${xPosition}px, ${yPosition}px)`,
userSelect: 'none',
}}
onMouseDown={handleMouseDown}
>
{children}
</div>
);
};
export default DraggableBox;