@servicetitan/assist-ui
Version:
ServiceTitan Assist UI Components
89 lines (74 loc) • 2.51 kB
text/typescript
import { MouseEvent, useCallback, useEffect, useState } from 'react';
export interface UseDraggableProps {
initialX?: number;
initialY?: number;
minVisible?: number;
width?: number;
}
export interface Position {
x: number;
y: number;
}
export const useDraggable = ({
initialX = window.innerWidth - 390,
initialY = 64,
minVisible = 50,
width = 390,
}: UseDraggableProps = {}) => {
const [position, setPosition] = useState<Position>({ x: initialX, y: initialY });
const [isDragging, setIsDragging] = useState(false);
const [dragOffset, setDragOffset] = useState<Position>({ x: 0, y: 0 });
const resetPosition = useCallback(() => {
setPosition({ x: initialX, y: initialY });
}, [initialX, initialY]);
const handleMouseDown = useCallback(
(e: MouseEvent) => {
setIsDragging(true);
setDragOffset({
x: e.clientX - position.x,
y: e.clientY - position.y,
});
},
[position]
);
const handleMouseMove = useCallback(
(e: MouseEvent) => {
if (!isDragging) {
return;
}
const newX = e.clientX - dragOffset.x;
const newY = e.clientY - dragOffset.y;
const maxX = window.innerWidth - minVisible;
const minX = -width + minVisible;
const maxY = window.innerHeight - minVisible;
setPosition({
x: Math.min(Math.max(newX, minX), maxX),
y: Math.min(Math.max(newY, minVisible), maxY),
});
},
[isDragging, dragOffset, minVisible, width]
);
const handleMouseUp = useCallback(() => {
setIsDragging(false);
}, []);
useEffect(() => {
if (isDragging) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
}
return () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
}, [isDragging, handleMouseMove, handleMouseUp]);
return {
position,
isDragging,
handleMouseDown,
resetPosition,
};
};