55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import { useCallback, useRef, useState } from "react";
|
|
|
|
interface UseResizableOptions {
|
|
/** Initial width in pixels */
|
|
initial: number;
|
|
/** Minimum width */
|
|
min: number;
|
|
/** Maximum width */
|
|
max: number;
|
|
}
|
|
|
|
interface UseResizableReturn {
|
|
width: number;
|
|
isDragging: boolean;
|
|
handleMouseDown: (e: React.MouseEvent) => void;
|
|
}
|
|
|
|
export function useResizable({ initial, min, max }: UseResizableOptions): UseResizableReturn {
|
|
const [width, setWidth] = useState(initial);
|
|
const [isDragging, setIsDragging] = useState(false);
|
|
const startX = useRef(0);
|
|
const startWidth = useRef(0);
|
|
|
|
const handleMouseDown = useCallback(
|
|
(e: React.MouseEvent) => {
|
|
e.preventDefault();
|
|
startX.current = e.clientX;
|
|
startWidth.current = width;
|
|
setIsDragging(true);
|
|
|
|
function onMouseMove(moveEvent: MouseEvent) {
|
|
const delta = moveEvent.clientX - startX.current;
|
|
const newWidth = Math.min(max, Math.max(min, startWidth.current + delta));
|
|
setWidth(newWidth);
|
|
}
|
|
|
|
function onMouseUp() {
|
|
setIsDragging(false);
|
|
document.removeEventListener("mousemove", onMouseMove);
|
|
document.removeEventListener("mouseup", onMouseUp);
|
|
document.body.style.cursor = "";
|
|
document.body.style.userSelect = "";
|
|
}
|
|
|
|
document.body.style.cursor = "col-resize";
|
|
document.body.style.userSelect = "none";
|
|
document.addEventListener("mousemove", onMouseMove);
|
|
document.addEventListener("mouseup", onMouseUp);
|
|
},
|
|
[width, min, max],
|
|
);
|
|
|
|
return { width, isDragging, handleMouseDown };
|
|
}
|