Skip to content

Instantly share code, notes, and snippets.

@himanshupal
Created June 4, 2023 14:18
Show Gist options
  • Save himanshupal/1ee1058b34a4c7d3e72af65791253a75 to your computer and use it in GitHub Desktop.
Save himanshupal/1ee1058b34a4c7d3e72af65791253a75 to your computer and use it in GitHub Desktop.
import { useEffect, useRef, useState } from 'react'
import { minPanelWidth } from '@/constants'
import style from './styles.module.less'
interface ISplitViewProps {
leftChild: React.ReactNode
rightChild: React.ReactNode
}
const SplitView: React.FC<ISplitViewProps> = ({ leftChild, rightChild }) => {
const [leftWidth, setLeftWidth] = useState<number | undefined>(undefined)
const splitPaneRef = useRef<HTMLDivElement>(null)
const leftRef = useRef<HTMLDivElement>(null)
const [separatorXPosition, setSeparatorXPosition] = useState<number | undefined>(undefined)
const [dragging, setDragging] = useState<boolean>(false)
const onMouseDown = (e: React.MouseEvent) => {
setSeparatorXPosition(e.clientX)
setDragging(true)
}
const onMouseUp = () => {
setDragging(false)
}
const onMouseMove = (e: MouseEvent) => {
if (!(dragging && leftWidth && separatorXPosition)) return
const newLeftWidth = leftWidth + e.clientX - separatorXPosition
setSeparatorXPosition(e.clientX)
if (newLeftWidth < minPanelWidth) {
setLeftWidth(minPanelWidth)
return
}
if (splitPaneRef.current) {
const splitPaneWidth = splitPaneRef.current.clientWidth
if (newLeftWidth > splitPaneWidth - minPanelWidth) {
setLeftWidth(splitPaneWidth - minPanelWidth)
return
}
}
setLeftWidth(newLeftWidth)
}
useEffect(() => {
if (!leftRef.current) return
if (!leftWidth) return setLeftWidth((document.body.clientWidth / 3) * 2)
leftRef.current.style.width = `${leftWidth}px`
}, [leftRef, leftWidth])
useEffect(() => {
void document.addEventListener('mousemove', onMouseMove)
void document.addEventListener('mouseup', onMouseUp)
return () => {
void document.removeEventListener('mousemove', onMouseMove)
void document.removeEventListener('mouseup', onMouseUp)
}
})
return (
<div className={style.splitView} ref={splitPaneRef}>
<div ref={leftRef}>{leftChild}</div>
<div className={style.dividerHitbox} onMouseDown={onMouseDown}>
<div className={style.divider} />
</div>
<div className={style.rightPanel}>{rightChild}</div>
</div>
)
}
export default SplitView
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment