UNPKG

@mapka/split-panel

Version:
152 lines (150 loc) 6.24 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; /** biome-ignore-all lint/correctness/useUniqueElementIds: later */ import { debounce } from "es-toolkit"; import { useCallback, useEffect, useRef } from "react"; const medianWidth = 10; export function SplitPanel({ rightPanel, leftPanel }) { const splitPanelRef = useRef(null); const splitPanelRec = useRef(null); const medianRef = useRef(null); const resizing = useRef(false); useEffect(() => { const handlePointerDown = (event) => { event.stopPropagation(); resizing.current = true; splitPanelRef.current?.setAttribute("data-resizing", "true"); }; medianRef.current?.addEventListener("pointerdown", handlePointerDown); return () => { medianRef.current?.removeEventListener("pointerdown", handlePointerDown); }; }, []); useEffect(() => { const handlePointerUp = (event) => { event.stopPropagation(); resizing.current = false; splitPanelRef.current?.setAttribute("data-resizing", "false"); }; medianRef.current?.addEventListener("pointerup", handlePointerUp); return () => { medianRef.current?.removeEventListener("pointerup", handlePointerUp); }; }, []); useEffect(() => { const handleMouseMove = (event) => { if (resizing.current && splitPanelRef.current) { if (splitPanelRec.current && splitPanelRec.current.width > 700) { const newMedianLeft = event.clientX - splitPanelRec.current.left; splitPanelRef.current.style.gridTemplateColumns = `calc(${newMedianLeft}px - ${medianWidth / 2}px) ${medianWidth}px 1fr`; } if (splitPanelRec.current && splitPanelRec.current.width < 700) { const newMedianTop = event.clientY - splitPanelRec.current.top; splitPanelRef.current.style.gridTemplateRows = `calc(${newMedianTop}px - ${medianWidth / 2}px) ${medianWidth}px 1fr`; } } }; splitPanelRef.current?.addEventListener("mousemove", handleMouseMove); return () => { splitPanelRef.current?.removeEventListener("mousemove", handleMouseMove); }; }, []); const handleInit = useCallback((element) => { if (!element) return; const rect = element.getBoundingClientRect(); splitPanelRef.current = element; splitPanelRec.current = rect; if (rect.width > 700) { element.setAttribute("data-direction", "col"); } else { element.setAttribute("data-direction", "row"); } }, []); useEffect(() => { if (splitPanelRef.current === null) return; const handleResize = debounce(() => { if (splitPanelRef.current) { const rect = splitPanelRef.current.getBoundingClientRect(); splitPanelRec.current = rect; if (rect.width > 700) { splitPanelRef.current.setAttribute("data-direction", "col"); splitPanelRef.current.style.removeProperty("grid-template-rows"); splitPanelRef.current.style.removeProperty("grid-template-columns"); } else { splitPanelRef.current.setAttribute("data-direction", "row"); splitPanelRef.current.style.removeProperty("grid-template-rows"); splitPanelRef.current.style.removeProperty("grid-template-columns"); } } }, 100); const resizer = new ResizeObserver(handleResize); resizer.observe(splitPanelRef.current); return () => { resizer.disconnect(); }; }, []); return (_jsxs(_Fragment, { children: [_jsx("style", { children: ` #mapka-split-panel[data-direction=col] { display: grid; grid-template-columns: 1fr 10px 1fr; grid-template-rows: 1fr; min-height: 100%; max-height: 100%; min-width: 100%; max-width: 100%; } #mapka-split-panel([data-resizing=true][data-direction=col]){ cursor: col-resize; } #mapka-split-panel[data-direction=row] { display: grid; grid-template-columns: 1fr; grid-template-rows: 1fr 10px 1fr; min-height: 100%; max-height: 100%; min-width: 100%; max-width: 100%; } #mapka-split-panel([data-resizing=true][data-direction=row]){ cursor: row-resize; } #mapka-split-panel([resizing]){ user-select: none; } #mapka-split-panel[data-direction=col] #median { inline-size: 10px; grid-column: 2 / 3; background: grey; } #mapka-split-panel[data-direction=row] #median { block-size: 10px; grid-row: 2 / 3; background: grey; } #mapka-split-panel[data-direction=col] #median:hover { cursor: col-resize; } #mapka-split-panel[data-direction=row] #median:hover { cursor: row-resize; } #mapka-split-panel[data-direction=col] #left-panel { grid-column: 1 / 2; grid-row: 1 / 1; } #mapka-split-panel[data-direction=row] #left-panel { grid-column: 1 / 1; grid-row: 1 / 2; max-width: 100%; overflow: hidden; } #mapka-split-panel[data-direction=col] #right-panel { grid-column: 3 / 4; grid-row: 1 / 1; max-width: 100%; overflow: hidden; } #mapka-split-panel[data-direction=row] #right-panel { grid-column: 1 / 1; grid-row: 3 / 4; } ` }), _jsxs("div", { id: "mapka-split-panel", "data-direction": "col", ref: handleInit, children: [_jsx("div", { id: "left-panel", children: leftPanel }), _jsx("div", { id: "median", ref: medianRef }), _jsx("div", { id: "right-panel", children: rightPanel })] })] })); }