diff --git a/frontend/components/screen/RealtimePreview.tsx b/frontend/components/screen/RealtimePreview.tsx index 0270ffa8..f1ca6e7d 100644 --- a/frontend/components/screen/RealtimePreview.tsx +++ b/frontend/components/screen/RealtimePreview.tsx @@ -401,22 +401,10 @@ export const RealtimePreviewDynamic: React.FC = ({ // 컴포넌트 스타일 계산 const isFlowWidget = type === "flow" || (type === "component" && (component as any).componentConfig?.type === "flow-widget"); + const isSectionPaper = type === "component" && (component as any).componentConfig?.type === "section-paper"; - // 높이 결정 로직 - let finalHeight = size?.height || 10; - if (isFlowWidget && actualHeight) { - finalHeight = actualHeight; - } - - // 🔍 디버깅: position.x 값 확인 const positionX = position?.x || 0; - console.log("🔍 RealtimePreview componentStyle 설정:", { - componentId: id, - positionX, - sizeWidth: size?.width, - styleWidth: style?.width, - willUse100Percent: positionX === 0, - }); + const positionY = position?.y || 0; // 너비 결정 로직: style.width (퍼센트) > 조건부 100% > size.width (픽셀) const getWidth = () => { @@ -432,20 +420,35 @@ export const RealtimePreviewDynamic: React.FC = ({ return size?.width || 200; }; + // 높이 결정 로직: style.height > actualHeight (Flow Widget) > size.height + const getHeight = () => { + // 1순위: style.height가 있으면 우선 사용 (픽셀/퍼센트 값) + if (style?.height) { + return style.height; + } + // 2순위: Flow Widget의 실제 측정 높이 + if (isFlowWidget && actualHeight) { + return actualHeight; + } + // 3순위: size.height 픽셀 값 + return size?.height || 10; + }; + const componentStyle = { position: "absolute" as const, ...style, // 먼저 적용하고 left: positionX, - top: position?.y || 0, + top: positionY, width: getWidth(), // 우선순위에 따른 너비 - height: finalHeight, + height: getHeight(), // 우선순위에 따른 높이 zIndex: position?.z || 1, // right 속성 강제 제거 right: undefined, }; // 선택된 컴포넌트 스타일 - const selectionStyle = isSelected + // Section Paper는 자체적으로 선택 상태 테두리를 처리하므로 outline 제거 + const selectionStyle = isSelected && !isSectionPaper ? { outline: "2px solid rgb(59, 130, 246)", outlineOffset: "2px", @@ -628,6 +631,24 @@ export const RealtimePreviewDynamic: React.FC = ({ )} + {/* 컴포넌트 타입 - 레지스트리 기반 렌더링 (Section Paper, Section Card 등) */} + {type === "component" && (() => { + const { DynamicComponentRenderer } = require("@/lib/registry/DynamicComponentRenderer"); + return ( + + {children} + + ); + })()} + {/* 위젯 타입 - 동적 렌더링 (파일 컴포넌트 제외) */} {type === "widget" && !isFileComponent(component) && (
diff --git a/frontend/components/screen/ScreenDesigner.tsx b/frontend/components/screen/ScreenDesigner.tsx index 0127c9d1..46d6ab37 100644 --- a/frontend/components/screen/ScreenDesigner.tsx +++ b/frontend/components/screen/ScreenDesigner.tsx @@ -4603,10 +4603,11 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD }); }} > - {/* 컨테이너, 그룹, 영역의 자식 컴포넌트들 렌더링 (레이아웃은 독립적으로 렌더링) */} + {/* 컨테이너, 그룹, 영역, 컴포넌트의 자식 컴포넌트들 렌더링 (레이아웃은 독립적으로 렌더링) */} {(component.type === "group" || component.type === "container" || - component.type === "area") && + component.type === "area" || + component.type === "component") && layout.components .filter((child) => child.parentId === component.id) .map((child) => { diff --git a/frontend/lib/registry/components/section-paper/SectionPaperComponent.tsx b/frontend/lib/registry/components/section-paper/SectionPaperComponent.tsx index 526bdfa1..fa7fc856 100644 --- a/frontend/lib/registry/components/section-paper/SectionPaperComponent.tsx +++ b/frontend/lib/registry/components/section-paper/SectionPaperComponent.tsx @@ -83,11 +83,22 @@ export function SectionPaperComponent({ ? { backgroundColor: config.customColor } : {}; + // 선택 상태 테두리 처리 (outline 사용하여 크기 영향 없음) + const selectionStyle = isDesignMode && isSelected + ? { + outline: "2px solid #3b82f6", + outlineOffset: "0px", // 크기에 영향 없이 딱 맞게 표시 + } + : {}; + return (
- {/* 디자인 모드에서 빈 상태 안내 */} - {isDesignMode && !children && ( + {/* 자식 컴포넌트들 */} + {children || (isDesignMode && (
📄 Section Paper
컴포넌트를 이곳에 배치하세요
- )} - - {/* 자식 컴포넌트들 */} - {children} + ))}
); }