I have implemented a div on the page that can be resized by dragging the border. However, the div has a maximum width, and once that width is exceeded, it no longer changes. But in this situation, the mouse pointer leaves the drag border.
Is there any way to keep the mouse pointer fixed on the border, even if the maximum width is exceeded, so that it doesn’t leave the border until the mouse is released?
i don’t know what to do
my code:
import { cn } from "@/lib/utils";
import { useEffect, useRef, useState } from "react";
type ExtraProps = {
width?: number;
maxWidth?: number;
minWidth?: number;
isLast?: boolean;
};
type ResizablePaneProps = React.HTMLAttributes<HTMLDivElement> & ExtraProps;
function ResizablePane({
className,
width: initialWidth,
maxWidth,
minWidth,
isLast = false,
...props
}: ResizablePaneProps) {
const [width, setWidth] = useState(initialWidth ?? 0);
const [isMouseDown, setIsMouseDown] = useState(false);
const divRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleMouseMove = (e:MouseEvent) => {
if (!isMouseDown) return;
const movement = e.movementX;
setWidth(calcMovement(width + movement, maxWidth, minWidth));
};
const handleMouseUp = () => setIsMouseDown(false);
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
}, [width, isMouseDown]);
useEffect(() => {
if (divRef.current && !initialWidth) {
// Set the state with the div's width
setWidth(divRef.current.offsetWidth);
}
}, []);
return (
<div
ref={divRef}
{...props}
className={cn(
calcClass({ width, maxWidth, minWidth, isLast }),
className
)}
style={{ width, maxWidth, minWidth }}
>
<h1 className="text-3xl">{width}</h1>
{String(isMouseDown)}
{props.children}
{!isLast && (
<div
className="absolute w-[5px] h-full -right-[3px] top-0 cursor-ew-resize flex justify-center z-10"
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
setIsMouseDown(true);
}}
>
<div className="w-[1px] bg-red-400 h-full"></div>
</div>
)}
</div>
);
}
/* Tailwind doesn’t include any sort of client-side runtime, so class names need to be statically extractable at build-time, and can’t depend on any sort of arbitrary dynamic values that change on the client. Use inline styles for these situations, or combine Tailwind with a CSS-in-JS library like Emotion if it makes sense for your project. */
function calcClass({ width, maxWidth, minWidth, isLast }: ExtraProps) {
const defaultCls = "relative";
// 过滤掉空字符串,以确保只有非空样式被添加到最终的类中
const nonEmpty = [width, maxWidth, minWidth].filter(Boolean);
return nonEmpty.length === 0 || isLast ? "grow " + defaultCls : defaultCls;
}
function calcMovement(width: number, maxWidth?: number, minWidth?: number) {
if (maxWidth && width >= maxWidth) {
return maxWidth;
} if (minWidth && width <= minWidth) {
return minWidth;
}
return width;
}
export default ResizablePane;