"use client"; import React from "react"; import { LayoutRendererProps } from "../BaseLayoutRenderer"; import { filterDOMProps } from "@/lib/utils/domPropsFilter"; /** * Flexbox 레이아웃 컴포넌트 */ export interface FlexboxLayoutProps extends LayoutRendererProps { renderer: any; // FlexboxLayoutRenderer 타입 } export const FlexboxLayout: React.FC = ({ layout, isDesignMode = false, isSelected = false, onClick, className = "", renderer, onZoneComponentDrop, onZoneClick, ...props }) => { if (!layout.layoutConfig.flexbox) { return (
플렉스박스 레이아웃 설정이 없습니다.
layoutConfig.flexbox가 필요합니다.
); } const flexConfig = layout.layoutConfig.flexbox; const containerStyle = renderer.getLayoutContainerStyle(); console.log("🔍 FlexboxLayout 컨테이너 설정:", { layoutId: layout.id, flexConfig, direction: flexConfig.direction, layoutConfig: layout.layoutConfig, }); // 플렉스박스 스타일 설정 (containerStyle보다 flex 속성을 우선 적용) const flexStyle: React.CSSProperties = { display: "flex !important" as any, flexDirection: flexConfig.direction, justifyContent: flexConfig.justify, alignItems: flexConfig.align, flexWrap: flexConfig.wrap, gap: `${flexConfig.gap}px`, // 레이아웃 컴포넌트의 높이 적용 - 부모 높이를 100% 따라가도록 height: layout.size?.height ? `${layout.size.height}px` : "100%", width: layout.size?.width ? `${layout.size.width}px` : "100%", minHeight: layout.size?.height ? `${layout.size.height}px` : "200px", // 최소 높이 보장 // containerStyle을 나중에 적용하되, flex 관련 속성은 덮어쓰지 않도록 ...containerStyle, // flex 속성들을 다시 강제 적용 (!important 사용) display: "flex !important" as any, flexDirection: flexConfig.direction, // 높이 관련 속성도 강제 적용 height: layout.size?.height ? `${layout.size.height}px` : "100%", minHeight: layout.size?.height ? `${layout.size.height}px` : "200px", }; console.log("🎨 FlexboxLayout 최종 스타일:", { display: flexStyle.display, flexDirection: flexStyle.flexDirection, height: flexStyle.height, width: flexStyle.width, }); // 각 존의 크기 정보 상세 로깅 console.log( "🔍 각 존의 크기 정보:", layout.zones?.map((zone) => ({ id: zone.id, size: zone.size, calculatedStyle: { width: zone.size?.width || "auto", height: zone.size?.height || defaultZoneHeight, minHeight: zone.size?.minHeight || "auto", maxHeight: zone.size?.maxHeight || "none", }, })), ); // 디자인 모드 스타일 if (isDesignMode) { flexStyle.border = isSelected ? "2px solid #3b82f6" : "1px solid #e2e8f0"; flexStyle.borderRadius = "8px"; flexStyle.padding = "8px"; } // DOM 안전한 props만 필터링 const domProps = filterDOMProps(props); return ( <>
{layout.zones.map((zone: any) => { const zoneChildren = renderer.getZoneChildren(zone.id); // 레이아웃 전체 높이 기준으로 존 높이 계산 const layoutHeight = layout.size?.height || 400; // 기본값 400px const defaultZoneHeight = flexConfig.direction === "column" ? Math.floor(layoutHeight / layout.zones.length) - 32 // 세로 배치시 존 개수로 나눔 : layoutHeight - 32; // 가로 배치시 전체 높이 사용 console.log("🔍 FlexboxLayout 높이 정보:", { layoutId: layout.id, layoutSize: layout.size, layoutHeight, defaultZoneHeight, flexDirection: flexConfig.direction, zoneId: zone.id, zoneSize: zone.size, }); // 플렉스 아이템 스타일 설정 const zoneStyle: React.CSSProperties = { flex: renderer.calculateFlexValue(zone, flexConfig.direction), // 카드 레이아웃처럼 항상 명확한 경계 표시 backgroundColor: "white", border: "1px solid #e5e7eb", borderRadius: "8px", padding: "16px", boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.1)", // 존의 크기: 개별 설정이 있으면 우선, 없으면 계산된 기본값 width: zone.size?.width ? typeof zone.size.width === "number" ? `${zone.size.width}px` : zone.size.width : "auto", height: zone.size?.height ? typeof zone.size.height === "number" ? `${zone.size.height}px` : zone.size.height : flexConfig.direction === "row" ? "100%" // 가로 배치일 때는 부모 높이를 100% 따라감 : `${defaultZoneHeight}px`, minHeight: zone.size?.minHeight ? typeof zone.size.minHeight === "number" ? `${zone.size.minHeight}px` : zone.size.minHeight : "100px", maxHeight: zone.size?.maxHeight ? typeof zone.size.maxHeight === "number" ? `${zone.size.maxHeight}px` : zone.size.maxHeight : "none", position: "relative", transition: "all 0.2s ease", margin: "4px", overflow: "hidden", display: "flex", flexDirection: "column", }; return (
{ e.currentTarget.style.borderColor = "#3b82f6"; e.currentTarget.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(59, 130, 246, 0.1)"; }} onMouseLeave={(e) => { e.currentTarget.style.borderColor = "#e5e7eb"; e.currentTarget.style.boxShadow = "0 1px 3px 0 rgba(0, 0, 0, 0.1)"; }} // 드롭 이벤트 제거 - 일반 캔버스 드롭만 사용 onClick={(e) => { e.stopPropagation(); if (onZoneClick) { onZoneClick(zone.id); } }} > {/* 존 라벨 */} {isDesignMode && (
{zone.name || zone.id}
)} {/* 존 내용 */}
{/* 존 안의 컴포넌트들을 절대 위치로 렌더링 */} {zoneChildren.map((child: any) => (
{renderer.renderChild(child)}
))}
); })} {/* 존이 없을 때 안내 메시지 */} {layout.zones.length === 0 && (
{ e.currentTarget.style.borderColor = "#3b82f6"; e.currentTarget.style.backgroundColor = "rgba(59, 130, 246, 0.05)"; }} onMouseLeave={(e) => { e.currentTarget.style.borderColor = isDesignMode ? "#cbd5e1" : "#e2e8f0"; e.currentTarget.style.backgroundColor = isDesignMode ? "rgba(148, 163, 184, 0.05)" : "rgba(248, 250, 252, 0.5)"; }} > {isDesignMode ? "플렉스박스 레이아웃에 존을 추가하세요" : "빈 레이아웃"}
)}
); };