134 lines
4.1 KiB
TypeScript
134 lines
4.1 KiB
TypeScript
import React, { useState, useRef, useCallback } from 'react'
|
|
|
|
interface SplitterProps {
|
|
direction: 'horizontal' | 'vertical'
|
|
initialSize: number
|
|
minSize?: number
|
|
maxSize?: number
|
|
children: [React.ReactNode, React.ReactNode]
|
|
className?: string
|
|
reverse?: boolean // İkinci panel için boyut kontrolü
|
|
}
|
|
|
|
export const Splitter: React.FC<SplitterProps> = ({
|
|
direction,
|
|
initialSize,
|
|
minSize = 200,
|
|
maxSize = 800,
|
|
children,
|
|
className = '',
|
|
reverse = false,
|
|
}) => {
|
|
const [size, setSize] = useState(initialSize)
|
|
const [isDragging, setIsDragging] = useState(false)
|
|
const splitterRef = useRef<HTMLDivElement>(null)
|
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
|
|
const handleMouseDown = useCallback(
|
|
(e: React.MouseEvent) => {
|
|
e.preventDefault()
|
|
setIsDragging(true)
|
|
|
|
const handleMouseMove = (e: MouseEvent) => {
|
|
if (!splitterRef.current || !containerRef.current) return
|
|
|
|
const rect = containerRef.current.getBoundingClientRect()
|
|
let newSize: number
|
|
|
|
if (direction === 'horizontal') {
|
|
if (reverse) {
|
|
// İkinci panel için boyut kontrolü - sağdan ölçüm
|
|
newSize = rect.right - e.clientX
|
|
} else {
|
|
// İlk panel için boyut kontrolü - soldan ölçüm
|
|
newSize = e.clientX - rect.left
|
|
}
|
|
} else {
|
|
if (reverse) {
|
|
// İkinci panel için boyut kontrolü - alttan ölçüm
|
|
newSize = rect.bottom - e.clientY
|
|
} else {
|
|
// İlk panel için boyut kontrolü - üstten ölçüm
|
|
newSize = e.clientY - rect.top
|
|
}
|
|
}
|
|
|
|
newSize = Math.max(minSize, Math.min(maxSize, newSize))
|
|
setSize(newSize)
|
|
}
|
|
|
|
const handleMouseUp = () => {
|
|
setIsDragging(false)
|
|
document.removeEventListener('mousemove', handleMouseMove)
|
|
document.removeEventListener('mouseup', handleMouseUp)
|
|
}
|
|
|
|
document.addEventListener('mousemove', handleMouseMove)
|
|
document.addEventListener('mouseup', handleMouseUp)
|
|
},
|
|
[direction, minSize, maxSize, reverse],
|
|
)
|
|
|
|
const isHorizontal = direction === 'horizontal'
|
|
|
|
return (
|
|
<div
|
|
ref={containerRef}
|
|
className={`flex flex-1 min-h-0 ${
|
|
isHorizontal ? 'flex-row' : 'flex-col'
|
|
} h-full w-full ${className}`}
|
|
>
|
|
{reverse ? (
|
|
<>
|
|
<div className="flex-1 h-screen overflow-hidden min-w-0 min-h-0">{children[0]}</div>
|
|
|
|
<div
|
|
ref={splitterRef}
|
|
className={`
|
|
${isHorizontal ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize'}
|
|
bg-gray-300 dark:bg-gray-700 hover:bg-blue-500 dark:hover:bg-blue-600 transition-colors duration-200 flex-shrink-0
|
|
${isDragging ? 'bg-blue-500 dark:bg-blue-600' : ''}
|
|
`}
|
|
onMouseDown={handleMouseDown}
|
|
/>
|
|
|
|
<div
|
|
style={{
|
|
[isHorizontal ? 'width' : 'height']: `${size}px`,
|
|
[isHorizontal ? 'minWidth' : 'minHeight']: `${size}px`,
|
|
[isHorizontal ? 'maxWidth' : 'maxHeight']: `${size}px`,
|
|
}}
|
|
className="overflow-hidden"
|
|
>
|
|
{children[1]}
|
|
</div>
|
|
</>
|
|
) : (
|
|
<>
|
|
<div
|
|
style={{
|
|
[isHorizontal ? 'width' : 'height']: `${size}px`,
|
|
[isHorizontal ? 'minWidth' : 'minHeight']: `${size}px`,
|
|
[isHorizontal ? 'maxWidth' : 'maxHeight']: `${size}px`,
|
|
}}
|
|
className="overflow-hidden"
|
|
>
|
|
{children[0]}
|
|
</div>
|
|
|
|
<div
|
|
ref={splitterRef}
|
|
className={`
|
|
${isHorizontal ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize'}
|
|
bg-gray-300 dark:bg-gray-700 hover:bg-blue-500 dark:hover:bg-blue-600 transition-colors duration-200 flex-shrink-0
|
|
${isDragging ? 'bg-blue-500 dark:bg-blue-600' : ''}
|
|
`}
|
|
onMouseDown={handleMouseDown}
|
|
/>
|
|
|
|
<div className="flex-1 h-screen overflow-hidden min-w-0 min-h-0">{children[1]}</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|