UNPKG

@servicetitan/assist-ui

Version:

ServiceTitan Assist UI Components

89 lines (74 loc) 2.51 kB
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, }; };