UNPKG

@servicetitan/assist-ui

Version:

ServiceTitan Atlas UI Components

121 lines (120 loc) 3.89 kB
import { useCallback, useEffect, useState } from 'react'; export const useDraggable = ({ initialX = window.innerWidth - 390, initialY = 64, minVisibleHorizontal = 390, minVisibleVertical = 56, width = 390 } = {})=>{ const [position, setPosition] = useState({ x: initialX, y: initialY }); const [isDragging, setIsDragging] = useState(false); const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 }); // Function to ensure position is within viewport boundaries const ensurePositionInViewport = useCallback((pos)=>{ const maxX = window.innerWidth - minVisibleHorizontal; const minX = -width + minVisibleHorizontal; const maxY = window.innerHeight - minVisibleVertical; return { x: Math.min(Math.max(pos.x, minX), maxX), y: Math.min(Math.max(pos.y, minVisibleVertical), maxY) }; }, [ minVisibleHorizontal, minVisibleVertical, width ]); // Function to recalculate initial position based on current viewport const recalculateInitialPosition = useCallback(()=>{ const newInitialX = window.innerWidth - width; return { x: newInitialX, y: initialY }; }, [ width, initialY ]); const resetPosition = useCallback(()=>{ const newInitialPos = recalculateInitialPosition(); setPosition(newInitialPos); }, [ recalculateInitialPosition ]); const handleMouseDown = useCallback((e)=>{ e.preventDefault(); setIsDragging(true); setDragOffset({ x: e.clientX - position.x, y: e.clientY - position.y }); }, [ position ]); const handleMouseMove = useCallback((e)=>{ if (!isDragging) { return; } const newX = e.clientX - dragOffset.x; const newY = e.clientY - dragOffset.y; const constrainedPosition = ensurePositionInViewport({ x: newX, y: newY }); setPosition(constrainedPosition); }, [ isDragging, dragOffset, ensurePositionInViewport ]); const handleMouseUp = useCallback(()=>{ setIsDragging(false); }, []); // Handle viewport resize const handleResize = useCallback(()=>{ const constrainedPosition = ensurePositionInViewport(position); setPosition(constrainedPosition); }, [ position, ensurePositionInViewport ]); useEffect(()=>{ if (isDragging) { // Prevent text selection while dragging document.body.style.userSelect = 'none'; document.body.style.webkitUserSelect = 'none'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); } return ()=>{ // Restore text selection document.body.style.userSelect = ''; document.body.style.webkitUserSelect = ''; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; }, [ isDragging, handleMouseMove, handleMouseUp ]); // Add resize listener useEffect(()=>{ window.addEventListener('resize', handleResize); return ()=>{ window.removeEventListener('resize', handleResize); }; }, [ handleResize ]); return { position, isDragging, handleMouseDown, resetPosition }; }; //# sourceMappingURL=use-draggable.js.map