-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathResizablePanel.jsx
More file actions
86 lines (76 loc) · 2.67 KB
/
Copy pathResizablePanel.jsx
File metadata and controls
86 lines (76 loc) · 2.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import React, { useState, useRef, useCallback, useEffect } from 'react';
export function ResizablePanel({ children, title, initialHeight = 440, minHeight = 200, maxHeight = 800 }) {
const [height, setHeight] = useState(initialHeight);
const [isResizing, setIsResizing] = useState(false);
const panelRef = useRef(null);
const startY = useRef(0);
const startHeight = useRef(0);
const handleMouseMove = useCallback((e) => {
if (!isResizing) return;
const deltaY = e.clientY - startY.current;
const newHeight = Math.min(Math.max(startHeight.current + deltaY, minHeight), maxHeight);
setHeight(newHeight);
}, [isResizing, minHeight, maxHeight]);
const handleMouseUp = useCallback(() => {
setIsResizing(false);
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
}, [handleMouseMove]);
useEffect(() => {
if (isResizing) {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
}
return () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
}, [isResizing, handleMouseMove, handleMouseUp]);
const handleMouseDown = useCallback((e) => {
setIsResizing(true);
startY.current = e.clientY;
startHeight.current = height;
e.preventDefault();
e.stopPropagation();
}, [height]);
return (
<section
ref={panelRef}
className="chart-panel p-3 fade-slide-in"
style={{ height: `${height}px` }}
aria-labelledby={`panel-title-${title.replace(/\s+/g, '-').toLowerCase()}`}
>
<div className="flex items-center justify-between mb-2">
<h3
id={`panel-title-${title.replace(/\s+/g, '-').toLowerCase()}`}
className="text-base font-semibold text-gray-800"
>
📊 {title}
</h3>
</div>
<div
className="chart-container"
style={{ height: `${height - 60}px` }}
role="img"
aria-label={`${title} 图表`}
>
{children}
</div>
<button
className="resize-handle"
onMouseDown={handleMouseDown}
title="拖拽调整图表高度"
aria-label={`调整 ${title} 图表高度`}
onKeyDown={(e) => {
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
e.preventDefault();
const delta = e.key === 'ArrowUp' ? -10 : 10;
const newHeight = Math.min(Math.max(height + delta, minHeight), maxHeight);
setHeight(newHeight);
}
}}
tabIndex={0}
/>
</section>
);
}