import React from "react"; import type { Placement } from "src/interfaces/placement"; import { getDefaultPanelSize, getMaxPanelHeight, getMaxPanelWidth, getPanelPosition, getPanelToggleTransforms, MIN_PANEL_HEIGHT, MIN_PANEL_WIDTH, roundToEven, } from "src/utilities"; import { ResizeHandleIcon } from "./icons/resize-handle-icon"; type Props = { placement: Placement; defaultWidth?: number; minWidth?: number; maxWidth?: number; defaultHeight?: number; minHeight?: number; maxHeight?: number; children: ({ resizing }: { resizing: string | null }) => React.ReactNode; onResize?: (width: number, height: number) => void; visible?: boolean; }; export const ResizablePane = ({ placement, visible, children }: Props) => { const [hover, setHover] = React.useState(false); const [resizing, setResizing] = React.useState< "lx" | "rx" | "ty" | "by" | null >(null); const [resizePosition, setResizePosition] = React.useState<{ x: number; y: number; } | null>(null); const [panelSize, setPanelSize] = React.useState< Record<"width" | "height", number> >(() => { const defaultSize = getDefaultPanelSize(placement); return { width: roundToEven(defaultSize.width), height: roundToEven(defaultSize.height), }; }); React.useEffect(() => { const handleResize = () => { setPanelSize((p) => { const defaultSize = getDefaultPanelSize(placement, p); return { width: roundToEven(defaultSize.width), height: roundToEven(defaultSize.height), }; }); }; handleResize(); window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, [placement]); React.useEffect(() => { const handleMouseUp = () => { setResizing(null); }; if (resizing !== null) { window.addEventListener("mouseup", handleMouseUp); return () => { window.removeEventListener("mouseup", handleMouseUp); }; } return; }, [resizing]); React.useEffect(() => { const currentCursor = document.body.style.cursor; if (resizing?.includes("x")) { document.body.style.cursor = "col-resize"; } else if (resizing?.includes("y")) { document.body.style.cursor = "row-resize"; } return () => { document.body.style.cursor = currentCursor; }; }, [resizing]); React.useEffect(() => { const handleMouseMove = (e: MouseEvent) => { if (resizing?.[1] === "x") { const diff = e.clientX - (resizePosition?.x ?? e.clientX); const newWidth = panelSize.width + (resizing === "lx" ? -diff : diff) * 2; setPanelSize((p) => ({ ...p, width: roundToEven( Math.min( getMaxPanelWidth(placement), Math.max(MIN_PANEL_WIDTH, newWidth), ), ), })); } else if (resizing?.[1] === "y") { const diff = e.clientY - (resizePosition?.y ?? e.clientY); const newHeight = panelSize.height + (resizing === "ty" ? -diff : diff) * 1; setPanelSize((p) => ({ ...p, height: roundToEven( Math.min( getMaxPanelHeight(placement), Math.max(MIN_PANEL_HEIGHT, newHeight), ), ), })); } }; if (resizing !== null) { window.addEventListener("mousemove", handleMouseMove); return () => { window.removeEventListener("mousemove", handleMouseMove); }; } return; }, [resizing, placement]); return (