"use client" import { useCallback, useEffect, useRef, useState, type ReactNode } from "react" import { cn } from "@/shared/lib/utils" interface ResizablePanelProps { /** 左侧最小宽度百分比 */ minLeft?: number /** 右侧最小宽度百分比 */ minRight?: number /** 初始左侧宽度百分比 */ initialLeft?: number left: ReactNode right: ReactNode className?: string } /** * 可拖拽分栏容器(左右两栏,中间分隔条可拖拽调整宽度)。 * 自实现,无新依赖。用于试卷编辑器左编辑右预览、阅卷式批改左题目右图片等场景。 */ export function ResizablePanel({ minLeft = 20, minRight = 20, initialLeft = 50, left, right, className, }: ResizablePanelProps) { const [leftPct, setLeftPct] = useState(initialLeft) const containerRef = useRef(null) const draggingRef = useRef(false) const onPointerDown = useCallback((e: React.PointerEvent) => { e.preventDefault() draggingRef.current = true document.body.style.cursor = "col-resize" document.body.style.userSelect = "none" }, []) useEffect(() => { const onMove = (e: PointerEvent) => { if (!draggingRef.current || !containerRef.current) return const rect = containerRef.current.getBoundingClientRect() const pct = ((e.clientX - rect.left) / rect.width) * 100 const clamped = Math.min(100 - minRight, Math.max(minLeft, pct)) setLeftPct(clamped) } const onUp = () => { draggingRef.current = false document.body.style.cursor = "" document.body.style.userSelect = "" } window.addEventListener("pointermove", onMove) window.addEventListener("pointerup", onUp) return () => { window.removeEventListener("pointermove", onMove) window.removeEventListener("pointerup", onUp) } }, [minLeft, minRight]) return (
{left}
{right}
) }