import classNames from "classnames"; import type { CSSProperties, MouseEvent as ReactMouseEvent } from "react"; import { useCallback, useRef, useState } from "react"; const START_DISTANCE = 7; export interface ResizeHandleEvent { x: number; y: number; xStart: number; yStart: number; } interface Props { style?: CSSProperties; className?: string; onResizeStart?: () => void; onResizeEnd?: () => void; onResizeMove?: (e: ResizeHandleEvent) => void; onReset?: () => void; side: "left" | "right" | "top"; justify: "center" | "end" | "start"; } export function ResizeHandle({ style, justify, className, onResizeStart, onResizeEnd, onResizeMove, onReset, side, }: Props) { const vertical = side === "top"; const [isResizing, setIsResizing] = useState(false); const moveState = useRef<{ move: (e: MouseEvent) => void; up: (e: MouseEvent) => void; calledStart: boolean; xStart: number; yStart: number; } | null>(null); const handlePointerDown = useCallback( (e: ReactMouseEvent) => { function move(e: MouseEvent) { if (moveState.current == null) return; const xDistance = moveState.current.xStart - e.clientX; const yDistance = moveState.current.yStart - e.clientY; const distance = Math.abs(vertical ? yDistance : xDistance); if (moveState.current.calledStart) { onResizeMove?.({ x: e.clientX, y: e.clientY, xStart: moveState.current.xStart, yStart: moveState.current.yStart, }); } else if (distance > START_DISTANCE) { onResizeStart?.(); moveState.current.calledStart = true; setIsResizing(true); } } function up() { setIsResizing(false); moveState.current = null; document.documentElement.removeEventListener("mousemove", move); document.documentElement.removeEventListener("mouseup", up); onResizeEnd?.(); } moveState.current = { calledStart: false, xStart: e.clientX, yStart: e.clientY, move, up }; document.documentElement.addEventListener("mousemove", move); document.documentElement.addEventListener("mouseup", up); }, [onResizeEnd, onResizeMove, onResizeStart, vertical], ); return (
{/* Show global overlay with cursor style to ensure cursor remains the same when moving quickly */} {isResizing && (
)}
); }