"use client";
import React, { useState, useCallback } from "react";
import { BaseLayoutRenderer, LayoutRendererProps } from "./BaseLayoutRenderer";
export default class SplitLayoutRenderer extends BaseLayoutRenderer {
render(): React.ReactElement {
const { layout, isDesignMode, isSelected, onClick, className } = this.props;
if (!layout.layoutConfig.split) {
return
분할 레이아웃 설정이 없습니다.
;
}
return (
);
}
}
interface SplitLayoutComponentProps {
layout: any;
isDesignMode?: boolean;
isSelected?: boolean;
onClick?: (e: React.MouseEvent) => void;
className?: string;
renderer: SplitLayoutRenderer;
}
const SplitLayoutComponent: React.FC = ({
layout,
isDesignMode,
isSelected,
onClick,
className,
renderer,
}) => {
const splitConfig = layout.layoutConfig.split;
const [sizes, setSizes] = useState(splitConfig.ratio || [50, 50]);
const [isDragging, setIsDragging] = useState(false);
const containerStyle = renderer.getLayoutContainerStyle();
// 분할 컨테이너 스타일
const splitStyle: React.CSSProperties = {
...containerStyle,
display: "flex",
flexDirection: splitConfig.direction === "horizontal" ? "row" : "column",
overflow: "hidden",
};
// 디자인 모드 스타일
if (isDesignMode) {
splitStyle.border = isSelected ? "2px solid #3b82f6" : "1px solid #e2e8f0";
splitStyle.borderRadius = "8px";
}
// 스플리터 드래그 핸들러
const handleSplitterDrag = useCallback(
(e: React.MouseEvent, index: number) => {
if (!splitConfig.resizable || !isDesignMode) return;
setIsDragging(true);
const startPos = splitConfig.direction === "horizontal" ? e.clientX : e.clientY;
const startSizes = [...sizes];
const handleMouseMove = (moveEvent: MouseEvent) => {
const currentPos = splitConfig.direction === "horizontal" ? moveEvent.clientX : moveEvent.clientY;
const delta = currentPos - startPos;
const containerSize =
splitConfig.direction === "horizontal"
? (e.currentTarget as HTMLElement).parentElement!.clientWidth
: (e.currentTarget as HTMLElement).parentElement!.clientHeight;
const deltaPercent = (delta / containerSize) * 100;
const newSizes = [...startSizes];
newSizes[index] = Math.max(splitConfig.minSize?.[index] || 10, Math.min(90, startSizes[index] + deltaPercent));
newSizes[index + 1] = Math.max(
splitConfig.minSize?.[index + 1] || 10,
Math.min(90, startSizes[index + 1] - deltaPercent),
);
setSizes(newSizes);
};
const handleMouseUp = () => {
setIsDragging(false);
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
},
[splitConfig, sizes, isDesignMode],
);
return (
!isDragging && renderer.props.onDragStart?.(e)}
onDragEnd={(e) => !isDragging && renderer.props.onDragEnd?.(e)}
>
{layout.zones.map((zone: any, index: number) => {
const zoneChildren = renderer.getZoneChildren(zone.id);
const isHorizontal = splitConfig.direction === "horizontal";
// 패널 크기 계산
const panelSize = sizes[index] || 100 / layout.zones.length;
const panelStyle: React.CSSProperties = {
[isHorizontal ? "width" : "height"]: `${panelSize}%`,
[isHorizontal ? "height" : "width"]: "100%",
overflow: "auto",
};
return (
{/* 패널 */}
{renderer.renderZone(zone, zoneChildren, {
style: panelStyle,
className: "split-panel",
})}
{/* 스플리터 (마지막 패널 제외) */}
{index < layout.zones.length - 1 && (
handleSplitterDrag(e, index)}
>
{/* 스플리터 핸들 */}
)}
);
})}
{/* 디자인 모드에서 존이 없을 때 안내 메시지 */}
{isDesignMode && layout.zones.length === 0 && (
분할 레이아웃에 존을 추가하세요
)}
);
};
// React 컴포넌트로 래핑
export const SplitLayout: React.FC = (props) => {
const renderer = new SplitLayoutRenderer(props);
return renderer.render();
};