import type { Component, JSX } from 'solid-js' import { createMemo, createSignal, onCleanup, onMount } from 'solid-js' export interface SplitPaneProps { left: JSX.Element right: JSX.Element initialWidth?: number minWidth?: number maxWidth?: number storageKey?: string } const SplitPane: Component = (props) => { const minWidth = createMemo(() => props.minWidth ?? 180) const maxWidth = createMemo(() => props.maxWidth ?? 600) const defaultWidth = createMemo(() => props.initialWidth ?? 256) const getInitialWidth = (): number => { if (props.storageKey) { const stored = localStorage.getItem(props.storageKey) if (stored) { const parsed = Number.parseInt(stored, 10) if (!Number.isNaN(parsed)) return Math.max(minWidth(), Math.min(maxWidth(), parsed)) } } return defaultWidth() } const [width, setWidth] = createSignal(getInitialWidth()) const [isDragging, setIsDragging] = createSignal(false) let containerRef: HTMLDivElement | undefined let leftPaneRef: HTMLDivElement | undefined const saveWidth = (w: number) => { if (props.storageKey) localStorage.setItem(props.storageKey, String(w)) } const handleMouseDown = (e: MouseEvent) => { e.preventDefault() setIsDragging(true) } const handleMouseMove = (e: MouseEvent) => { if (!isDragging() || !containerRef) return const rect = containerRef.getBoundingClientRect() const newWidth = e.clientX - rect.left const clampedWidth = Math.max(minWidth(), Math.min(maxWidth(), newWidth)) setWidth(clampedWidth) if (leftPaneRef) leftPaneRef.style.width = `${clampedWidth}px` } const handleMouseUp = () => { if (isDragging()) { setIsDragging(false) saveWidth(width()) } } const handleDblClick = () => { const w = defaultWidth() setWidth(w) if (leftPaneRef) leftPaneRef.style.width = `${w}px` saveWidth(w) } onMount(() => { document.addEventListener('mousemove', handleMouseMove) document.addEventListener('mouseup', handleMouseUp) }) onCleanup(() => { document.removeEventListener('mousemove', handleMouseMove) document.removeEventListener('mouseup', handleMouseUp) }) return (
(leftPaneRef = el)} class="shrink-0 overflow-hidden" style={{ width: `${width()}px` }} > {props.left}
{props.right}
) } export default SplitPane