"use client"; import React from "react"; import { ComponentData, WebType, WidgetComponent } from "@/types/screen"; import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRenderer"; import { Database, Type, Hash, List, AlignLeft, CheckSquare, Radio, Calendar, Code, Building, File, } from "lucide-react"; // 컴포넌트 렌더러들 자동 등록 import "@/lib/registry/components"; interface RealtimePreviewProps { component: ComponentData; isSelected?: boolean; isDesignMode?: boolean; // 편집 모드 여부 onClick?: (e?: React.MouseEvent) => void; onDoubleClick?: (e?: React.MouseEvent) => void; // 더블클릭 핸들러 추가 onDragStart?: (e: React.DragEvent) => void; onDragEnd?: () => void; onGroupToggle?: (groupId: string) => void; // 그룹 접기/펼치기 children?: React.ReactNode; // 그룹 내 자식 컴포넌트들 selectedScreen?: any; onZoneComponentDrop?: (e: React.DragEvent, zoneId: string, layoutId: string) => void; // 존별 드롭 핸들러 onZoneClick?: (zoneId: string) => void; // 존 클릭 핸들러 onConfigChange?: (config: any) => void; // 설정 변경 핸들러 } // 동적 위젯 타입 아이콘 (레지스트리에서 조회) const getWidgetIcon = (widgetType: WebType | undefined): React.ReactNode => { if (!widgetType) return ; const iconMap: Record = { text: Aa, number: , decimal: , date: , datetime: , select: , dropdown: , textarea: , boolean: , checkbox: , radio: , code: , entity: , file: , email: @, tel: , button: BTN, }; return iconMap[widgetType] || ; }; export const RealtimePreviewDynamic: React.FC = ({ component, isSelected = false, isDesignMode = true, // 기본값은 편집 모드 onClick, onDoubleClick, onDragStart, onDragEnd, onGroupToggle, children, selectedScreen, onZoneComponentDrop, onZoneClick, onConfigChange, }) => { const { id, type, position, size, style: componentStyle } = component; // 선택 상태에 따른 스타일 (z-index 낮춤 - 패널과 모달보다 아래) const selectionStyle = isSelected ? { outline: "2px solid rgb(59, 130, 246)", outlineOffset: "2px", zIndex: 20, } : {}; // 컴포넌트 기본 스타일 - 레이아웃은 항상 맨 아래 // 너비 우선순위: style.width > size.width (픽셀값) const getWidth = () => { // 1순위: style.width가 있으면 우선 사용 if (componentStyle?.width) { return componentStyle.width; } // 2순위: size.width (픽셀) if (component.componentConfig?.type === "table-list") { return `${Math.max(size?.width || 120, 120)}px`; } return `${size?.width || 100}px`; }; const getHeight = () => { // 1순위: style.height가 있으면 우선 사용 if (componentStyle?.height) { return componentStyle.height; } // 2순위: size.height (픽셀) if (component.componentConfig?.type === "table-list") { return `${Math.max(size?.height || 200, 200)}px`; } return `${size?.height || 40}px`; }; const baseStyle = { left: `${position.x}px`, top: `${position.y}px`, width: getWidth(), height: getHeight(), // 모든 컴포넌트 고정 높이로 변경 zIndex: component.type === "layout" ? 1 : position.z || 2, // 레이아웃은 z-index 1, 다른 컴포넌트는 2 이상 ...componentStyle, // style.width와 style.height는 이미 getWidth/getHeight에서 처리했으므로 중복 적용됨 }; const handleClick = (e: React.MouseEvent) => { e.stopPropagation(); onClick?.(e); }; const handleDoubleClick = (e: React.MouseEvent) => { e.stopPropagation(); onDoubleClick?.(e); }; const handleDragStart = (e: React.DragEvent) => { e.stopPropagation(); onDragStart?.(e); }; const handleDragEnd = () => { onDragEnd?.(); }; return (
{/* 동적 컴포넌트 렌더링 */}
{/* 선택된 컴포넌트 정보 표시 */} {isSelected && (
{type === "widget" && (
{getWidgetIcon((component as WidgetComponent).widgetType)} {(component as WidgetComponent).widgetType || "widget"}
)} {type !== "widget" && (
{component.componentConfig?.type || type}
)}
)}
); }; // 기존 RealtimePreview와의 호환성을 위한 export export { RealtimePreviewDynamic as RealtimePreview }; export default RealtimePreviewDynamic;