可拖动调整大小的面板
This commit is contained in:
151
packages/editor-app/src/components/ResizablePanel.tsx
Normal file
151
packages/editor-app/src/components/ResizablePanel.tsx
Normal file
@@ -0,0 +1,151 @@
|
||||
import { useState, useRef, useEffect, ReactNode } from 'react';
|
||||
import '../styles/ResizablePanel.css';
|
||||
|
||||
interface ResizablePanelProps {
|
||||
direction: 'horizontal' | 'vertical';
|
||||
leftOrTop: ReactNode;
|
||||
rightOrBottom: ReactNode;
|
||||
defaultSize?: number;
|
||||
minSize?: number;
|
||||
maxSize?: number;
|
||||
side?: 'left' | 'right' | 'top' | 'bottom';
|
||||
}
|
||||
|
||||
export function ResizablePanel({
|
||||
direction,
|
||||
leftOrTop,
|
||||
rightOrBottom,
|
||||
defaultSize = 250,
|
||||
minSize = 150,
|
||||
maxSize = 600,
|
||||
side = 'left'
|
||||
}: ResizablePanelProps) {
|
||||
const [size, setSize] = useState(defaultSize);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDragging) return;
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const rect = containerRef.current.getBoundingClientRect();
|
||||
let newSize: number;
|
||||
|
||||
if (direction === 'horizontal') {
|
||||
if (side === 'right') {
|
||||
newSize = rect.right - e.clientX;
|
||||
} else {
|
||||
newSize = e.clientX - rect.left;
|
||||
}
|
||||
} else {
|
||||
if (side === 'bottom') {
|
||||
newSize = rect.bottom - e.clientY;
|
||||
} else {
|
||||
newSize = e.clientY - rect.top;
|
||||
}
|
||||
}
|
||||
|
||||
newSize = Math.max(minSize, Math.min(maxSize, newSize));
|
||||
setSize(newSize);
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
};
|
||||
}, [isDragging, direction, minSize, maxSize, side]);
|
||||
|
||||
const handleMouseDown = () => {
|
||||
setIsDragging(true);
|
||||
};
|
||||
|
||||
const className = `resizable-panel resizable-panel-${direction}`;
|
||||
const resizerClassName = `resizer resizer-${direction}`;
|
||||
|
||||
if (direction === 'horizontal') {
|
||||
if (side === 'right') {
|
||||
return (
|
||||
<div ref={containerRef} className={className}>
|
||||
<div className="panel-section" style={{ flex: 1 }}>
|
||||
{leftOrTop}
|
||||
</div>
|
||||
<div
|
||||
className={resizerClassName}
|
||||
onMouseDown={handleMouseDown}
|
||||
style={{ cursor: isDragging ? 'ew-resize' : 'col-resize' }}
|
||||
>
|
||||
<div className="resizer-handle" />
|
||||
</div>
|
||||
<div className="panel-section" style={{ width: `${size}px` }}>
|
||||
{rightOrBottom}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div ref={containerRef} className={className}>
|
||||
<div className="panel-section" style={{ width: `${size}px` }}>
|
||||
{leftOrTop}
|
||||
</div>
|
||||
<div
|
||||
className={resizerClassName}
|
||||
onMouseDown={handleMouseDown}
|
||||
style={{ cursor: isDragging ? 'ew-resize' : 'col-resize' }}
|
||||
>
|
||||
<div className="resizer-handle" />
|
||||
</div>
|
||||
<div className="panel-section" style={{ flex: 1 }}>
|
||||
{rightOrBottom}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (side === 'bottom') {
|
||||
return (
|
||||
<div ref={containerRef} className={className}>
|
||||
<div className="panel-section" style={{ flex: 1 }}>
|
||||
{leftOrTop}
|
||||
</div>
|
||||
<div
|
||||
className={resizerClassName}
|
||||
onMouseDown={handleMouseDown}
|
||||
style={{ cursor: isDragging ? 'ns-resize' : 'row-resize' }}
|
||||
>
|
||||
<div className="resizer-handle" />
|
||||
</div>
|
||||
<div className="panel-section" style={{ height: `${size}px` }}>
|
||||
{rightOrBottom}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div ref={containerRef} className={className}>
|
||||
<div className="panel-section" style={{ height: `${size}px` }}>
|
||||
{leftOrTop}
|
||||
</div>
|
||||
<div
|
||||
className={resizerClassName}
|
||||
onMouseDown={handleMouseDown}
|
||||
style={{ cursor: isDragging ? 'ns-resize' : 'row-resize' }}
|
||||
>
|
||||
<div className="resizer-handle" />
|
||||
</div>
|
||||
<div className="panel-section" style={{ flex: 1 }}>
|
||||
{rightOrBottom}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user