109 lines
2.5 KiB
TypeScript
109 lines
2.5 KiB
TypeScript
import React, { useState, useEffect } from "react";
|
|
|
|
type ResizableProps = {
|
|
children: React.ReactNode;
|
|
isHorizontal: boolean;
|
|
initialSize: number;
|
|
minimumSize: number;
|
|
maximumSize: number;
|
|
};
|
|
|
|
export default function Resizable({
|
|
children,
|
|
isHorizontal = true,
|
|
initialSize,
|
|
minimumSize,
|
|
maximumSize,
|
|
}: ResizableProps) {
|
|
const [dimension, setDimension] = useState(initialSize);
|
|
const [previousDragPosition, setPreviousDragPosition] = useState<{
|
|
x: number;
|
|
y: number;
|
|
} | null>(null);
|
|
|
|
const handleDragStart = (e: React.MouseEvent<HTMLDivElement>): void => {
|
|
setPreviousDragPosition({
|
|
x: e.clientX,
|
|
y: e.clientY,
|
|
});
|
|
};
|
|
|
|
const handleDrag = (e: MouseEvent) => {
|
|
if (previousDragPosition === null) {
|
|
return;
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
let offset = 0;
|
|
if (isHorizontal) {
|
|
offset = e.clientX - previousDragPosition.x;
|
|
} else {
|
|
offset = e.clientY - previousDragPosition.y;
|
|
}
|
|
let newValue = dimension - offset;
|
|
if (minimumSize != null) {
|
|
newValue = Math.max(minimumSize, newValue);
|
|
}
|
|
if (maximumSize != null) {
|
|
newValue = Math.min(maximumSize, newValue);
|
|
}
|
|
setDimension(newValue);
|
|
setPreviousDragPosition({
|
|
x: e.clientX,
|
|
y: e.clientY,
|
|
});
|
|
};
|
|
|
|
const handleDragEnd = () => {
|
|
setPreviousDragPosition(null);
|
|
};
|
|
|
|
useEffect(() => {
|
|
window.addEventListener("mousemove", handleDrag);
|
|
window.addEventListener("mouseup", handleDragEnd);
|
|
return () => {
|
|
window.removeEventListener("mousemove", handleDrag);
|
|
window.removeEventListener("mouseup", handleDragEnd);
|
|
};
|
|
}, [handleDrag, handleDragEnd]);
|
|
|
|
const style = () => {
|
|
let formatted = dimension + "px";
|
|
|
|
if (isHorizontal) {
|
|
return {
|
|
width: formatted,
|
|
};
|
|
} else {
|
|
return {
|
|
height: formatted,
|
|
};
|
|
}
|
|
};
|
|
|
|
const classes = () => {
|
|
if (isHorizontal) {
|
|
return "flex flex-none relative";
|
|
} else {
|
|
return "flex flex-none relative";
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div style={style()} className={classes()}>
|
|
<div className={"flex-grow"} style={{ width: "inherit" }}>
|
|
{children}
|
|
</div>
|
|
<div
|
|
className={
|
|
isHorizontal
|
|
? "w-1 h-full absolute my-0 -ml-[1px] transition-all cursor-col-resize hover:bg-indigo-700 hover:opacity-100"
|
|
: "h-1 w-full transition-all cursor-row-resize hover:bg-indigo-700 hover:opacity-100"
|
|
}
|
|
onMouseDown={handleDragStart}
|
|
></div>
|
|
</div>
|
|
);
|
|
}
|