레이아웃 컴포넌트 단순화
This commit is contained in:
parent
4da06b2a56
commit
77a6b50761
|
|
@ -28,7 +28,9 @@ interface RealtimePreviewProps {
|
||||||
onDragEnd?: () => void;
|
onDragEnd?: () => void;
|
||||||
onGroupToggle?: (groupId: string) => void; // 그룹 접기/펼치기
|
onGroupToggle?: (groupId: string) => void; // 그룹 접기/펼치기
|
||||||
children?: React.ReactNode; // 그룹 내 자식 컴포넌트들
|
children?: React.ReactNode; // 그룹 내 자식 컴포넌트들
|
||||||
selectedScreen?: any; // 선택된 화면 정보
|
selectedScreen?: any;
|
||||||
|
onZoneComponentDrop?: (e: React.DragEvent, zoneId: string, layoutId: string) => void; // 존별 드롭 핸들러
|
||||||
|
onZoneClick?: (zoneId: string) => void; // 존 클릭 핸들러
|
||||||
}
|
}
|
||||||
|
|
||||||
// 동적 위젯 타입 아이콘 (레지스트리에서 조회)
|
// 동적 위젯 타입 아이콘 (레지스트리에서 조회)
|
||||||
|
|
@ -67,6 +69,8 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
|
||||||
onGroupToggle,
|
onGroupToggle,
|
||||||
children,
|
children,
|
||||||
selectedScreen,
|
selectedScreen,
|
||||||
|
onZoneComponentDrop,
|
||||||
|
onZoneClick,
|
||||||
}) => {
|
}) => {
|
||||||
const { id, type, position, size, style: componentStyle } = component;
|
const { id, type, position, size, style: componentStyle } = component;
|
||||||
|
|
||||||
|
|
@ -79,13 +83,13 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
|
||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
// 컴포넌트 기본 스타일
|
// 컴포넌트 기본 스타일 - 레이아웃은 항상 맨 아래
|
||||||
const baseStyle = {
|
const baseStyle = {
|
||||||
left: `${position.x}px`,
|
left: `${position.x}px`,
|
||||||
top: `${position.y}px`,
|
top: `${position.y}px`,
|
||||||
width: `${size.width}px`,
|
width: `${size?.width || 100}px`,
|
||||||
height: `${size.height}px`,
|
height: `${size?.height || 36}px`,
|
||||||
zIndex: position.z || 1,
|
zIndex: component.type === "layout" ? 1 : position.z || 2, // 레이아웃은 z-index 1, 다른 컴포넌트는 2 이상
|
||||||
...componentStyle,
|
...componentStyle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -123,6 +127,8 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
|
||||||
onDragEnd={onDragEnd}
|
onDragEnd={onDragEnd}
|
||||||
children={children}
|
children={children}
|
||||||
selectedScreen={selectedScreen}
|
selectedScreen={selectedScreen}
|
||||||
|
onZoneComponentDrop={onZoneComponentDrop}
|
||||||
|
onZoneClick={onZoneClick}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1345,9 +1345,81 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||||
[layout, gridInfo, screenResolution, snapToGrid, saveToHistory, openPanel],
|
[layout, gridInfo, screenResolution, snapToGrid, saveToHistory, openPanel],
|
||||||
);
|
);
|
||||||
|
|
||||||
// 컴포넌트 드래그 처리
|
// handleZoneComponentDrop은 handleComponentDrop으로 대체됨
|
||||||
|
|
||||||
|
// 존 클릭 핸들러
|
||||||
|
const handleZoneClick = useCallback((zoneId: string) => {
|
||||||
|
console.log("🎯 존 클릭:", zoneId);
|
||||||
|
// 필요시 존 선택 로직 추가
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 웹타입별 기본 설정 생성 함수를 상위로 이동
|
||||||
|
const getDefaultWebTypeConfig = useCallback((webType: string) => {
|
||||||
|
switch (webType) {
|
||||||
|
case "button":
|
||||||
|
return {
|
||||||
|
actionType: "custom",
|
||||||
|
variant: "default",
|
||||||
|
confirmationMessage: "",
|
||||||
|
popupTitle: "",
|
||||||
|
popupContent: "",
|
||||||
|
navigateUrl: "",
|
||||||
|
};
|
||||||
|
case "date":
|
||||||
|
return {
|
||||||
|
format: "YYYY-MM-DD",
|
||||||
|
showTime: false,
|
||||||
|
placeholder: "날짜를 선택하세요",
|
||||||
|
};
|
||||||
|
case "number":
|
||||||
|
return {
|
||||||
|
format: "integer",
|
||||||
|
placeholder: "숫자를 입력하세요",
|
||||||
|
};
|
||||||
|
case "select":
|
||||||
|
return {
|
||||||
|
options: [
|
||||||
|
{ label: "옵션 1", value: "option1" },
|
||||||
|
{ label: "옵션 2", value: "option2" },
|
||||||
|
{ label: "옵션 3", value: "option3" },
|
||||||
|
],
|
||||||
|
multiple: false,
|
||||||
|
searchable: false,
|
||||||
|
placeholder: "옵션을 선택하세요",
|
||||||
|
};
|
||||||
|
case "file":
|
||||||
|
return {
|
||||||
|
accept: ["*/*"],
|
||||||
|
maxSize: 10485760, // 10MB
|
||||||
|
multiple: false,
|
||||||
|
showPreview: true,
|
||||||
|
autoUpload: false,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 컴포넌트 드래그 처리 (캔버스 레벨 드롭)
|
||||||
const handleComponentDrop = useCallback(
|
const handleComponentDrop = useCallback(
|
||||||
(e: React.DragEvent, component: any) => {
|
(e: React.DragEvent, component?: any, zoneId?: string, layoutId?: string) => {
|
||||||
|
// 존별 드롭인 경우 dragData에서 컴포넌트 정보 추출
|
||||||
|
if (!component) {
|
||||||
|
const dragData = e.dataTransfer.getData("application/json");
|
||||||
|
if (!dragData) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsedData = JSON.parse(dragData);
|
||||||
|
if (parsedData.type === "component") {
|
||||||
|
component = parsedData.component;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("드래그 데이터 파싱 오류:", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
const rect = canvasRef.current?.getBoundingClientRect();
|
const rect = canvasRef.current?.getBoundingClientRect();
|
||||||
if (!rect) return;
|
if (!rect) return;
|
||||||
|
|
||||||
|
|
@ -1377,53 +1449,6 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||||
snappedPosition,
|
snappedPosition,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 웹타입별 기본 설정 생성
|
|
||||||
const getDefaultWebTypeConfig = (webType: string) => {
|
|
||||||
switch (webType) {
|
|
||||||
case "button":
|
|
||||||
return {
|
|
||||||
actionType: "custom",
|
|
||||||
variant: "default",
|
|
||||||
confirmationMessage: "",
|
|
||||||
popupTitle: "",
|
|
||||||
popupContent: "",
|
|
||||||
navigateUrl: "",
|
|
||||||
};
|
|
||||||
case "date":
|
|
||||||
return {
|
|
||||||
format: "YYYY-MM-DD",
|
|
||||||
showTime: false,
|
|
||||||
placeholder: "날짜를 선택하세요",
|
|
||||||
};
|
|
||||||
case "number":
|
|
||||||
return {
|
|
||||||
format: "integer",
|
|
||||||
placeholder: "숫자를 입력하세요",
|
|
||||||
};
|
|
||||||
case "select":
|
|
||||||
return {
|
|
||||||
options: [
|
|
||||||
{ label: "옵션 1", value: "option1" },
|
|
||||||
{ label: "옵션 2", value: "option2" },
|
|
||||||
{ label: "옵션 3", value: "option3" },
|
|
||||||
],
|
|
||||||
multiple: false,
|
|
||||||
searchable: false,
|
|
||||||
placeholder: "옵션을 선택하세요",
|
|
||||||
};
|
|
||||||
case "file":
|
|
||||||
return {
|
|
||||||
accept: ["*/*"],
|
|
||||||
maxSize: 10485760, // 10MB
|
|
||||||
multiple: false,
|
|
||||||
showPreview: true,
|
|
||||||
autoUpload: false,
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 새 컴포넌트 생성
|
// 새 컴포넌트 생성
|
||||||
console.log("🔍 ScreenDesigner handleComponentDrop:", {
|
console.log("🔍 ScreenDesigner handleComponentDrop:", {
|
||||||
componentName: component.name,
|
componentName: component.name,
|
||||||
|
|
@ -3105,8 +3130,10 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||||
onDragStart={(e) => startComponentDrag(component, e)}
|
onDragStart={(e) => startComponentDrag(component, e)}
|
||||||
onDragEnd={endDrag}
|
onDragEnd={endDrag}
|
||||||
selectedScreen={selectedScreen}
|
selectedScreen={selectedScreen}
|
||||||
|
// onZoneComponentDrop 제거
|
||||||
|
onZoneClick={handleZoneClick}
|
||||||
>
|
>
|
||||||
{/* 컨테이너, 그룹, 영역의 자식 컴포넌트들 렌더링 */}
|
{/* 컨테이너, 그룹, 영역의 자식 컴포넌트들 렌더링 (레이아웃은 독립적으로 렌더링) */}
|
||||||
{(component.type === "group" || component.type === "container" || component.type === "area") &&
|
{(component.type === "group" || component.type === "container" || component.type === "area") &&
|
||||||
layout.components
|
layout.components
|
||||||
.filter((child) => child.parentId === component.id)
|
.filter((child) => child.parentId === component.id)
|
||||||
|
|
@ -3182,6 +3209,8 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||||
onDragStart={(e) => startComponentDrag(child, e)}
|
onDragStart={(e) => startComponentDrag(child, e)}
|
||||||
onDragEnd={endDrag}
|
onDragEnd={endDrag}
|
||||||
selectedScreen={selectedScreen}
|
selectedScreen={selectedScreen}
|
||||||
|
// onZoneComponentDrop 제거
|
||||||
|
onZoneClick={handleZoneClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
@ -3290,7 +3319,7 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||||
id="layouts"
|
id="layouts"
|
||||||
title="레이아웃"
|
title="레이아웃"
|
||||||
isOpen={panelStates.layouts?.isOpen || false}
|
isOpen={panelStates.layouts?.isOpen || false}
|
||||||
onClose={() => closePanelState("layouts")}
|
onClose={() => closePanel("layouts")}
|
||||||
position="left"
|
position="left"
|
||||||
width={380}
|
width={380}
|
||||||
height={700}
|
height={700}
|
||||||
|
|
@ -3304,6 +3333,8 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||||
};
|
};
|
||||||
e.dataTransfer.setData("application/json", JSON.stringify(dragData));
|
e.dataTransfer.setData("application/json", JSON.stringify(dragData));
|
||||||
}}
|
}}
|
||||||
|
gridSettings={layout.gridSettings || { columns: 12, gap: 16, padding: 16, snapToGrid: true }}
|
||||||
|
screenResolution={screenResolution}
|
||||||
/>
|
/>
|
||||||
</FloatingPanel>
|
</FloatingPanel>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { Grid, Layout, LayoutDashboard, Table, Navigation, FileText, Building, Search, Plus } from "lucide-react";
|
import { Grid, Layout, LayoutDashboard, Table, Navigation, FileText, Building, Search, Plus } from "lucide-react";
|
||||||
import { LAYOUT_CATEGORIES, LayoutCategory } from "@/types/layout";
|
import { LAYOUT_CATEGORIES, LayoutCategory } from "@/types/layout";
|
||||||
import { LayoutRegistry } from "@/lib/registry/LayoutRegistry";
|
import { LayoutRegistry } from "@/lib/registry/LayoutRegistry";
|
||||||
|
import { calculateGridInfo, calculateWidthFromColumns } from "@/lib/utils/gridUtils";
|
||||||
|
|
||||||
// 카테고리 아이콘 매핑
|
// 카테고리 아이콘 매핑
|
||||||
const CATEGORY_ICONS = {
|
const CATEGORY_ICONS = {
|
||||||
|
|
@ -36,9 +37,25 @@ interface LayoutsPanelProps {
|
||||||
onDragStart: (e: React.DragEvent, layoutData: any) => void;
|
onDragStart: (e: React.DragEvent, layoutData: any) => void;
|
||||||
onLayoutSelect?: (layoutDefinition: any) => void;
|
onLayoutSelect?: (layoutDefinition: any) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
gridSettings?: {
|
||||||
|
columns: number;
|
||||||
|
gap: number;
|
||||||
|
padding: number;
|
||||||
|
snapToGrid: boolean;
|
||||||
|
};
|
||||||
|
screenResolution?: {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function LayoutsPanel({ onDragStart, onLayoutSelect, className }: LayoutsPanelProps) {
|
export default function LayoutsPanel({
|
||||||
|
onDragStart,
|
||||||
|
onLayoutSelect,
|
||||||
|
className,
|
||||||
|
gridSettings,
|
||||||
|
screenResolution,
|
||||||
|
}: LayoutsPanelProps) {
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
const [selectedCategory, setSelectedCategory] = useState<string>("all");
|
const [selectedCategory, setSelectedCategory] = useState<string>("all");
|
||||||
|
|
||||||
|
|
@ -78,6 +95,29 @@ export default function LayoutsPanel({ onDragStart, onLayoutSelect, className }:
|
||||||
|
|
||||||
// 레이아웃 드래그 시작 핸들러
|
// 레이아웃 드래그 시작 핸들러
|
||||||
const handleDragStart = (e: React.DragEvent, layoutDefinition: any) => {
|
const handleDragStart = (e: React.DragEvent, layoutDefinition: any) => {
|
||||||
|
// 격자 기반 동적 크기 계산
|
||||||
|
let calculatedSize = layoutDefinition.defaultSize || { width: 400, height: 300 };
|
||||||
|
|
||||||
|
if (gridSettings && screenResolution && layoutDefinition.id === "card-layout") {
|
||||||
|
// 카드 레이아웃의 경우 8그리드 컬럼에 맞는 너비 계산
|
||||||
|
const gridInfo = calculateGridInfo(screenResolution.width, screenResolution.height, gridSettings);
|
||||||
|
const calculatedWidth = calculateWidthFromColumns(8, gridInfo, gridSettings);
|
||||||
|
|
||||||
|
calculatedSize = {
|
||||||
|
width: Math.max(calculatedWidth, 400), // 최소 400px 보장
|
||||||
|
height: 400, // 높이는 고정
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("🎯 카드 레이아웃 동적 크기 계산:", {
|
||||||
|
gridColumns: 8,
|
||||||
|
screenResolution,
|
||||||
|
gridSettings,
|
||||||
|
gridInfo,
|
||||||
|
calculatedWidth,
|
||||||
|
finalSize: calculatedSize,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 새 레이아웃 컴포넌트 데이터 생성
|
// 새 레이아웃 컴포넌트 데이터 생성
|
||||||
const layoutData = {
|
const layoutData = {
|
||||||
id: `layout_${Date.now()}`,
|
id: `layout_${Date.now()}`,
|
||||||
|
|
@ -88,8 +128,9 @@ export default function LayoutsPanel({ onDragStart, onLayoutSelect, className }:
|
||||||
children: [],
|
children: [],
|
||||||
allowedComponentTypes: [],
|
allowedComponentTypes: [],
|
||||||
position: { x: 0, y: 0 },
|
position: { x: 0, y: 0 },
|
||||||
size: layoutDefinition.defaultSize || { width: 400, height: 300 },
|
size: calculatedSize,
|
||||||
label: layoutDefinition.name,
|
label: layoutDefinition.name,
|
||||||
|
gridColumns: layoutDefinition.id === "card-layout" ? 8 : 1, // 카드 레이아웃은 기본 8그리드
|
||||||
};
|
};
|
||||||
|
|
||||||
// 드래그 데이터 설정
|
// 드래그 데이터 설정
|
||||||
|
|
@ -192,4 +233,3 @@ export default function LayoutsPanel({ onDragStart, onLayoutSelect, className }:
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -191,9 +191,11 @@ const PropertiesPanelComponent: React.FC<PropertiesPanelProps> = ({
|
||||||
positionX: currentPosition.x.toString(),
|
positionX: currentPosition.x.toString(),
|
||||||
positionY: currentPosition.y.toString(),
|
positionY: currentPosition.y.toString(),
|
||||||
positionZ: selectedComponent?.position.z?.toString() || "1",
|
positionZ: selectedComponent?.position.z?.toString() || "1",
|
||||||
width: selectedComponent?.size.width?.toString() || "0",
|
width: selectedComponent?.size?.width?.toString() || "0",
|
||||||
height: selectedComponent?.size.height?.toString() || "0",
|
height: selectedComponent?.size?.height?.toString() || "0",
|
||||||
gridColumns: selectedComponent?.gridColumns?.toString() || "1",
|
gridColumns:
|
||||||
|
selectedComponent?.gridColumns?.toString() ||
|
||||||
|
(selectedComponent?.type === "layout" && (selectedComponent as any)?.layoutType === "card-layout" ? "8" : "1"),
|
||||||
labelText: selectedComponent?.style?.labelText || selectedComponent?.label || "",
|
labelText: selectedComponent?.style?.labelText || selectedComponent?.label || "",
|
||||||
labelFontSize: selectedComponent?.style?.labelFontSize || "12px",
|
labelFontSize: selectedComponent?.style?.labelFontSize || "12px",
|
||||||
labelColor: selectedComponent?.style?.labelColor || "#374151",
|
labelColor: selectedComponent?.style?.labelColor || "#374151",
|
||||||
|
|
@ -244,14 +246,18 @@ const PropertiesPanelComponent: React.FC<PropertiesPanelProps> = ({
|
||||||
description: area?.description || "",
|
description: area?.description || "",
|
||||||
positionX: currentPos.x.toString(),
|
positionX: currentPos.x.toString(),
|
||||||
positionY: currentPos.y.toString(),
|
positionY: currentPos.y.toString(),
|
||||||
positionZ: selectedComponent.position.z?.toString() || "1",
|
positionZ: selectedComponent?.position?.z?.toString() || "1",
|
||||||
width: selectedComponent.size.width?.toString() || "0",
|
width: selectedComponent?.size?.width?.toString() || "0", // 안전한 접근
|
||||||
height: selectedComponent.size.height?.toString() || "0",
|
height: selectedComponent?.size?.height?.toString() || "0", // 안전한 접근
|
||||||
gridColumns: selectedComponent.gridColumns?.toString() || "1",
|
gridColumns:
|
||||||
labelText: selectedComponent.style?.labelText || selectedComponent.label || "",
|
selectedComponent?.gridColumns?.toString() ||
|
||||||
labelFontSize: selectedComponent.style?.labelFontSize || "12px",
|
(selectedComponent?.type === "layout" && (selectedComponent as any)?.layoutType === "card-layout"
|
||||||
labelColor: selectedComponent.style?.labelColor || "#374151",
|
? "8"
|
||||||
labelMarginBottom: selectedComponent.style?.labelMarginBottom || "4px",
|
: "1"),
|
||||||
|
labelText: selectedComponent?.style?.labelText || selectedComponent?.label || "",
|
||||||
|
labelFontSize: selectedComponent?.style?.labelFontSize || "12px",
|
||||||
|
labelColor: selectedComponent?.style?.labelColor || "#374151",
|
||||||
|
labelMarginBottom: selectedComponent?.style?.labelMarginBottom || "4px",
|
||||||
required: widget?.required || false,
|
required: widget?.required || false,
|
||||||
readonly: widget?.readonly || false,
|
readonly: widget?.readonly || false,
|
||||||
labelDisplay: selectedComponent.style?.labelDisplay !== false,
|
labelDisplay: selectedComponent.style?.labelDisplay !== false,
|
||||||
|
|
@ -584,7 +590,7 @@ const PropertiesPanelComponent: React.FC<PropertiesPanelProps> = ({
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const newValue = e.target.value;
|
const newValue = e.target.value;
|
||||||
setLocalInputs((prev) => ({ ...prev, width: newValue }));
|
setLocalInputs((prev) => ({ ...prev, width: newValue }));
|
||||||
onUpdateProperty("size", { ...selectedComponent.size, width: Number(newValue) });
|
onUpdateProperty("size", { ...(selectedComponent.size || {}), width: Number(newValue) });
|
||||||
}}
|
}}
|
||||||
className="mt-1"
|
className="mt-1"
|
||||||
/>
|
/>
|
||||||
|
|
@ -601,7 +607,7 @@ const PropertiesPanelComponent: React.FC<PropertiesPanelProps> = ({
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const newValue = e.target.value;
|
const newValue = e.target.value;
|
||||||
setLocalInputs((prev) => ({ ...prev, height: newValue }));
|
setLocalInputs((prev) => ({ ...prev, height: newValue }));
|
||||||
onUpdateProperty("size", { ...selectedComponent.size, height: Number(newValue) });
|
onUpdateProperty("size", { ...(selectedComponent.size || {}), height: Number(newValue) });
|
||||||
}}
|
}}
|
||||||
className="mt-1"
|
className="mt-1"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
2. [CLI를 이용한 자동 생성](#cli를-이용한-자동-생성)
|
2. [CLI를 이용한 자동 생성](#cli를-이용한-자동-생성)
|
||||||
3. [생성된 파일 구조](#생성된-파일-구조)
|
3. [생성된 파일 구조](#생성된-파일-구조)
|
||||||
4. [레이아웃 커스터마이징](#레이아웃-커스터마이징)
|
4. [레이아웃 커스터마이징](#레이아웃-커스터마이징)
|
||||||
5. [카드 레이아웃 상세 가이드](#카드-레이아웃-상세-가이드)웃
|
5. [카드 레이아웃 상세 가이드](#카드-레이아웃-상세-가이드)
|
||||||
6. [고급 설정](#고급-설정)
|
6. [고급 설정](#고급-설정)
|
||||||
7. [문제 해결](#문제-해결)
|
7. [문제 해결](#문제-해결)
|
||||||
|
|
||||||
|
|
@ -846,6 +846,62 @@ const getColumnLabel = (columnName: string) => {
|
||||||
<span>{getColumnLabel(columnName)}:</span>
|
<span>{getColumnLabel(columnName)}:</span>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 9. 레이아웃 드롭 시 오류 발생 문제 (9월 11일 해결됨)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ❌ 문제: 복잡한 존별 드롭 로직으로 인한 오류
|
||||||
|
- Runtime TypeError: Cannot read properties of undefined (reading 'width')
|
||||||
|
- 다중선택 기능 중단
|
||||||
|
- 존별 드롭 이벤트 충돌
|
||||||
|
|
||||||
|
// ✅ 해결: 드롭 시스템 완전 단순화
|
||||||
|
- 모든 존별 드롭 로직 제거
|
||||||
|
- 일반 캔버스 드롭만 사용
|
||||||
|
- 레이아웃은 시각적 가이드 역할만
|
||||||
|
- z-index 기반 레이어 분리 (레이아웃=1, 컴포넌트=2+)
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 드롭 시스템 단순화 후 장점
|
||||||
|
|
||||||
|
- ✅ **안정성**: 복잡한 이벤트 체인 제거로 오류 가능성 감소
|
||||||
|
- ✅ **일관성**: 모든 영역에서 동일한 드롭 동작
|
||||||
|
- ✅ **성능**: 불필요한 prop 전달 및 매핑 로직 제거
|
||||||
|
- ✅ **유지보수**: 단순한 구조로 디버깅 및 수정 용이
|
||||||
|
|
||||||
|
##### 새로운 레이아웃 개발 시 주의사항
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ 올바른 레이아웃 구현
|
||||||
|
export const YourLayoutLayout: React.FC<YourLayoutProps> = ({ layout, isDesignMode, ...props }) => {
|
||||||
|
// 🚫 존별 드롭 이벤트 구현 금지
|
||||||
|
// onDrop, onDragOver 등 드롭 관련 이벤트 추가하지 않음
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="your-layout">
|
||||||
|
{layout.zones.map((zone) => (
|
||||||
|
<div
|
||||||
|
key={zone.id}
|
||||||
|
className="zone-area"
|
||||||
|
// 🚫 드롭 이벤트 추가 금지
|
||||||
|
// onDrop={...} ❌
|
||||||
|
// onDragOver={...} ❌
|
||||||
|
>
|
||||||
|
{/* 존 내용 */}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<style jsx>{`
|
||||||
|
.your-layout {
|
||||||
|
/* z-index는 1로 고정 (레이아웃 레이어) */
|
||||||
|
z-index: 1;
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### 디버깅 도구
|
### 디버깅 도구
|
||||||
|
|
||||||
#### 브라우저 개발자 도구
|
#### 브라우저 개발자 도구
|
||||||
|
|
@ -1025,6 +1081,53 @@ node scripts/create-layout.js form-layout --category=form --zones=3 --descriptio
|
||||||
- ✅ **시각적 피드백**: 모든 레이아웃에서 존 경계 명확히 표시
|
- ✅ **시각적 피드백**: 모든 레이아웃에서 존 경계 명확히 표시
|
||||||
- ✅ **React 경고 해결**: Key prop, DOM prop 전달 등 모든 경고 해결
|
- ✅ **React 경고 해결**: Key prop, DOM prop 전달 등 모든 경고 해결
|
||||||
|
|
||||||
|
#### 🔧 드롭 시스템 대폭 단순화 (9월 11일 추가)
|
||||||
|
|
||||||
|
기존의 복잡한 존별 드롭 시스템을 완전히 제거하고 단순한 캔버스 드롭 방식으로 통일했습니다:
|
||||||
|
|
||||||
|
##### 변경 사항
|
||||||
|
|
||||||
|
- ✅ **복잡한 드롭 로직 제거**: `onZoneComponentDrop`, `handleZoneComponentDrop` 등 모든 존별 드롭 이벤트 제거
|
||||||
|
- ✅ **일반 캔버스 드롭만 사용**: 모든 드롭이 `handleComponentDrop`으로 통일
|
||||||
|
- ✅ **레이아웃은 시각적 가이드 역할**: 레이아웃 존은 배치 가이드라인 역할만 수행
|
||||||
|
- ✅ **z-index 기반 레이어링**: 레이아웃 z-index=1, 컴포넌트 z-index=2+로 설정
|
||||||
|
- ✅ **prop 전달 체인 단순화**: 불필요한 prop 매핑 및 전달 로직 제거
|
||||||
|
|
||||||
|
##### 새로운 동작 방식
|
||||||
|
|
||||||
|
**이전 (복잡한 방식)**:
|
||||||
|
```
|
||||||
|
컴포넌트 드래그 → 레이아웃 존 감지 → 존별 드롭 이벤트 → 복잡한 매핑 → 오류 발생
|
||||||
|
```
|
||||||
|
|
||||||
|
**현재 (단순한 방식)**:
|
||||||
|
```
|
||||||
|
컴포넌트 드래그 → 캔버스에 드롭 → 일반 handleComponentDrop만 실행 → 안정적 동작
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 해결된 문제들
|
||||||
|
|
||||||
|
- ✅ **Runtime TypeError 해결**: `selectedComponent.size.width` undefined 오류 완전 해결
|
||||||
|
- ✅ **다중선택 복구**: 드래그로 다중선택 기능 정상화
|
||||||
|
- ✅ **안정적 드롭**: 레이아웃 위든 어디든 일관된 드롭 동작
|
||||||
|
- ✅ **코드 단순화**: 복잡한 존별 로직 제거로 유지보수성 향상
|
||||||
|
|
||||||
|
##### 기술적 변경점
|
||||||
|
|
||||||
|
1. **GridLayout, FlexboxLayout**: `onDragOver`, `onDrop` 이벤트 핸들러 제거
|
||||||
|
2. **ScreenDesigner**: `onZoneComponentDrop` prop 전달 제거
|
||||||
|
3. **DynamicComponentRenderer**: `onComponentDrop` 매핑 로직 제거
|
||||||
|
4. **DynamicLayoutRenderer**: 존별 prop 전달 제거
|
||||||
|
5. **RealtimePreviewDynamic**: z-index 기반 레이어링 적용
|
||||||
|
|
||||||
|
##### 개발자 가이드
|
||||||
|
|
||||||
|
새로운 시스템에서는:
|
||||||
|
- 🚫 **존별 드롭 로직 구현 금지**: 모든 드롭은 캔버스 레벨에서 처리
|
||||||
|
- ✅ **시각적 가이드만 제공**: 레이아웃은 배치 가이드라인 역할만
|
||||||
|
- ✅ **z-index로 레이어 관리**: 레이아웃=1, 컴포넌트=2+ 설정
|
||||||
|
- ✅ **단순한 이벤트 처리**: 복잡한 이벤트 체인 대신 직접적인 핸들링
|
||||||
|
|
||||||
#### 개발자 도구 강화
|
#### 개발자 도구 강화
|
||||||
|
|
||||||
- ✅ **디버깅 로그**: 카드 설정 로드, 데이터 가져오기 등 상세 로깅
|
- ✅ **디버깅 로그**: 카드 설정 로드, 데이터 가져오기 등 상세 로깅
|
||||||
|
|
@ -1042,9 +1145,38 @@ node scripts/create-layout.js form-layout --category=form --zones=3 --descriptio
|
||||||
|
|
||||||
### 🔮 향후 계획
|
### 🔮 향후 계획
|
||||||
|
|
||||||
|
#### 새로운 레이아웃 타입
|
||||||
- **Table Layout**: 데이터 테이블 전용 레이아웃
|
- **Table Layout**: 데이터 테이블 전용 레이아웃
|
||||||
- **Form Layout**: 폼 입력에 최적화된 레이아웃
|
- **Form Layout**: 폼 입력에 최적화된 레이아웃
|
||||||
- **Dashboard Layout**: 위젯 배치에 특화된 레이아웃
|
- **Dashboard Layout**: 위젯 배치에 특화된 레이아웃
|
||||||
- **Mobile Responsive**: 모바일 대응 반응형 레이아웃
|
- **Mobile Responsive**: 모바일 대응 반응형 레이아웃
|
||||||
|
|
||||||
|
#### 시스템 개선
|
||||||
|
- **레이아웃 테마 시스템**: 다크/라이트 모드 지원
|
||||||
|
- **레이아웃 스타일 프리셋**: 미리 정의된 스타일 템플릿
|
||||||
|
- **레이아웃 애니메이션**: 전환 효과 및 인터랙션 개선
|
||||||
|
- **성능 최적화**: 가상화 및 지연 로딩 적용
|
||||||
|
|
||||||
|
#### 개발자 도구
|
||||||
|
- **레이아웃 빌더 GUI**: 코드 없이 레이아웃 생성 도구
|
||||||
|
- **실시간 프리뷰**: 레이아웃 편집 중 실시간 미리보기
|
||||||
|
- **레이아웃 디버거**: 시각적 디버깅 도구
|
||||||
|
- **성능 모니터링**: 레이아웃 렌더링 성능 분석
|
||||||
|
|
||||||
|
### 🎯 중요한 변화: 단순화된 드롭 시스템
|
||||||
|
|
||||||
|
**2025년 9월 11일**부터 모든 레이아웃에서 **복잡한 존별 드롭 로직이 완전히 제거**되었습니다.
|
||||||
|
|
||||||
|
새로운 시스템의 핵심 원칙:
|
||||||
|
- 🎯 **레이아웃 = 시각적 가이드**: 배치 참고용으로만 사용
|
||||||
|
- 🎯 **캔버스 = 실제 배치**: 모든 컴포넌트는 캔버스에 자유롭게 배치
|
||||||
|
- 🎯 **z-index = 레이어 분리**: 레이아웃(1) 위에 컴포넌트(2+) 배치
|
||||||
|
- 🎯 **단순함 = 안정성**: 복잡한 로직 제거로 오류 최소화
|
||||||
|
|
||||||
|
이 변화로 인해:
|
||||||
|
- ✅ 모든 드롭 관련 오류 해결
|
||||||
|
- ✅ 다중선택 기능 정상화
|
||||||
|
- ✅ 레이아웃 개발이 더욱 단순해짐
|
||||||
|
- ✅ 시스템 전체 안정성 크게 향상
|
||||||
|
|
||||||
더 자세한 정보가 필요하면 각 레이아웃의 `README.md` 파일을 참고하거나, 브라우저 개발자 도구에서 `window.__LAYOUT_REGISTRY__.help()`를 실행해보세요! 🚀
|
더 자세한 정보가 필요하면 각 레이아웃의 `README.md` 파일을 참고하거나, 브라우저 개발자 도구에서 `window.__LAYOUT_REGISTRY__.help()`를 실행해보세요! 🚀
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ export interface ComponentRenderer {
|
||||||
onDragStart?: (e: React.DragEvent) => void;
|
onDragStart?: (e: React.DragEvent) => void;
|
||||||
onDragEnd?: () => void;
|
onDragEnd?: () => void;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
onZoneComponentDrop?: (e: React.DragEvent, zoneId: string, layoutId: string) => void;
|
||||||
|
onZoneClick?: (zoneId: string) => void;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}): React.ReactElement;
|
}): React.ReactElement;
|
||||||
}
|
}
|
||||||
|
|
@ -89,6 +91,8 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
|
||||||
onDragStart={onDragStart}
|
onDragStart={onDragStart}
|
||||||
onDragEnd={onDragEnd}
|
onDragEnd={onDragEnd}
|
||||||
onUpdateLayout={props.onUpdateLayout}
|
onUpdateLayout={props.onUpdateLayout}
|
||||||
|
// onComponentDrop 제거 - 일반 캔버스 드롭만 사용
|
||||||
|
onZoneClick={props.onZoneClick}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,14 @@ export interface DynamicLayoutRendererProps {
|
||||||
isDesignMode?: boolean;
|
isDesignMode?: boolean;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
onClick?: (e: React.MouseEvent) => void;
|
onClick?: (e: React.MouseEvent) => void;
|
||||||
onZoneClick?: (zoneId: string, e: React.MouseEvent) => void;
|
onZoneClick?: (zoneId: string) => void;
|
||||||
onComponentDrop?: (zoneId: string, component: ComponentData, e: React.DragEvent) => void;
|
onComponentDrop?: (e: React.DragEvent, zoneId: string, layoutId: string) => void;
|
||||||
onDragStart?: (e: React.DragEvent) => void;
|
onDragStart?: (e: React.DragEvent) => void;
|
||||||
onDragEnd?: (e: React.DragEvent) => void;
|
onDragEnd?: (e: React.DragEvent) => void;
|
||||||
onUpdateLayout?: (updatedLayout: LayoutComponent) => void; // 레이아웃 업데이트 콜백
|
onUpdateLayout?: (updatedLayout: LayoutComponent) => void; // 레이아웃 업데이트 콜백
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
|
[key: string]: any; // 추가 props 허용
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DynamicLayoutRenderer: React.FC<DynamicLayoutRendererProps> = ({
|
export const DynamicLayoutRenderer: React.FC<DynamicLayoutRendererProps> = ({
|
||||||
|
|
@ -77,7 +78,7 @@ export const DynamicLayoutRenderer: React.FC<DynamicLayoutRendererProps> = ({
|
||||||
isSelected={isSelected}
|
isSelected={isSelected}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onZoneClick={onZoneClick}
|
onZoneClick={onZoneClick}
|
||||||
onComponentDrop={onComponentDrop}
|
// onComponentDrop 제거
|
||||||
onDragStart={onDragStart}
|
onDragStart={onDragStart}
|
||||||
onDragEnd={onDragEnd}
|
onDragEnd={onDragEnd}
|
||||||
onUpdateLayout={onUpdateLayout}
|
onUpdateLayout={onUpdateLayout}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ export const AccordionLayout: React.FC<AccordionLayoutProps> = ({
|
||||||
onClick,
|
onClick,
|
||||||
className = "",
|
className = "",
|
||||||
renderer,
|
renderer,
|
||||||
|
onZoneComponentDrop,
|
||||||
|
onZoneClick,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
if (!layout.layoutConfig.accordion) {
|
if (!layout.layoutConfig.accordion) {
|
||||||
|
|
@ -57,7 +59,6 @@ export const AccordionLayout: React.FC<AccordionLayoutProps> = ({
|
||||||
onSelectComponent,
|
onSelectComponent,
|
||||||
isDesignMode: _isDesignMode,
|
isDesignMode: _isDesignMode,
|
||||||
allComponents,
|
allComponents,
|
||||||
onZoneClick,
|
|
||||||
onComponentDrop,
|
onComponentDrop,
|
||||||
onDragStart,
|
onDragStart,
|
||||||
onDragEnd,
|
onDragEnd,
|
||||||
|
|
@ -205,7 +206,7 @@ const AccordionSection: React.FC<{
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (onComponentDrop) {
|
if (onComponentDrop) {
|
||||||
onComponentDrop(e, zone.id); // 존 ID와 함께 드롭 이벤트 전달
|
onComponentDrop(e, zone.id, layout.id); // 존 ID와 레이아웃 ID를 함께 전달
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ export const CardLayoutLayout: React.FC<CardLayoutProps> = ({
|
||||||
className="hover:border-blue-500 hover:shadow-md"
|
className="hover:border-blue-500 hover:shadow-md"
|
||||||
>
|
>
|
||||||
{/* 존 라벨 */}
|
{/* 존 라벨 */}
|
||||||
<div className="absolute left-2 top-2 z-10">
|
<div className="absolute top-2 left-2 z-10">
|
||||||
<div className="rounded bg-blue-500 px-2 py-1 text-xs text-white">{zone.name}</div>
|
<div className="rounded bg-blue-500 px-2 py-1 text-xs text-white">{zone.name}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -247,7 +247,7 @@ export const CardLayoutLayout: React.FC<CardLayoutProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={idx} className="flex justify-between text-xs">
|
<div key={idx} className="flex justify-between text-xs">
|
||||||
<span className="capitalize text-gray-500">{getColumnLabel(columnName)}:</span>
|
<span className="text-gray-500 capitalize">{getColumnLabel(columnName)}:</span>
|
||||||
<span className="font-medium text-gray-700">{value}</span>
|
<span className="font-medium text-gray-700">{value}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ export const CardLayoutDefinition = createLayoutDefinition({
|
||||||
category: "dashboard",
|
category: "dashboard",
|
||||||
icon: "grid-3x3",
|
icon: "grid-3x3",
|
||||||
component: CardLayoutWrapper,
|
component: CardLayoutWrapper,
|
||||||
|
defaultSize: { width: 800, height: 400 },
|
||||||
defaultConfig: {
|
defaultConfig: {
|
||||||
cardLayout: {
|
cardLayout: {
|
||||||
columns: 3,
|
columns: 3,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ export const FlexboxLayout: React.FC<FlexboxLayoutProps> = ({
|
||||||
onClick,
|
onClick,
|
||||||
className = "",
|
className = "",
|
||||||
renderer,
|
renderer,
|
||||||
|
onZoneComponentDrop,
|
||||||
|
onZoneClick,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
if (!layout.layoutConfig.flexbox) {
|
if (!layout.layoutConfig.flexbox) {
|
||||||
|
|
@ -98,7 +100,6 @@ export const FlexboxLayout: React.FC<FlexboxLayoutProps> = ({
|
||||||
onSelectComponent,
|
onSelectComponent,
|
||||||
isDesignMode: _isDesignMode,
|
isDesignMode: _isDesignMode,
|
||||||
allComponents,
|
allComponents,
|
||||||
onZoneClick,
|
|
||||||
onComponentDrop,
|
onComponentDrop,
|
||||||
onDragStart,
|
onDragStart,
|
||||||
onDragEnd,
|
onDragEnd,
|
||||||
|
|
@ -200,17 +201,7 @@ export const FlexboxLayout: React.FC<FlexboxLayoutProps> = ({
|
||||||
e.currentTarget.style.borderColor = "#e5e7eb";
|
e.currentTarget.style.borderColor = "#e5e7eb";
|
||||||
e.currentTarget.style.boxShadow = "0 1px 3px 0 rgba(0, 0, 0, 0.1)";
|
e.currentTarget.style.boxShadow = "0 1px 3px 0 rgba(0, 0, 0, 0.1)";
|
||||||
}}
|
}}
|
||||||
onDragOver={(e) => {
|
// 드롭 이벤트 제거 - 일반 캔버스 드롭만 사용
|
||||||
e.preventDefault();
|
|
||||||
e.dataTransfer.dropEffect = "copy";
|
|
||||||
}}
|
|
||||||
onDrop={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
if (onComponentDrop) {
|
|
||||||
onComponentDrop(e, zone.id); // 존 ID와 함께 드롭 이벤트 전달
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (onZoneClick) {
|
if (onZoneClick) {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ export const GridLayout: React.FC<GridLayoutProps> = ({
|
||||||
onClick,
|
onClick,
|
||||||
className = "",
|
className = "",
|
||||||
renderer,
|
renderer,
|
||||||
|
onZoneComponentDrop,
|
||||||
|
onZoneClick,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
if (!layout.layoutConfig.grid) {
|
if (!layout.layoutConfig.grid) {
|
||||||
|
|
@ -66,7 +68,6 @@ export const GridLayout: React.FC<GridLayoutProps> = ({
|
||||||
onSelectComponent,
|
onSelectComponent,
|
||||||
isDesignMode: _isDesignMode,
|
isDesignMode: _isDesignMode,
|
||||||
allComponents,
|
allComponents,
|
||||||
onZoneClick,
|
|
||||||
onComponentDrop,
|
onComponentDrop,
|
||||||
onDragStart,
|
onDragStart,
|
||||||
onDragEnd,
|
onDragEnd,
|
||||||
|
|
@ -158,17 +159,7 @@ export const GridLayout: React.FC<GridLayoutProps> = ({
|
||||||
e.currentTarget.style.borderColor = "#e5e7eb";
|
e.currentTarget.style.borderColor = "#e5e7eb";
|
||||||
e.currentTarget.style.boxShadow = "0 1px 3px 0 rgba(0, 0, 0, 0.1)";
|
e.currentTarget.style.boxShadow = "0 1px 3px 0 rgba(0, 0, 0, 0.1)";
|
||||||
}}
|
}}
|
||||||
onDragOver={(e) => {
|
// 드롭 이벤트 제거 - 일반 캔버스 드롭만 사용
|
||||||
e.preventDefault();
|
|
||||||
e.dataTransfer.dropEffect = "copy";
|
|
||||||
}}
|
|
||||||
onDrop={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
if (onComponentDrop) {
|
|
||||||
onComponentDrop(e, zone.id); // 존 ID와 함께 드롭 이벤트 전달
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (onZoneClick) {
|
if (onZoneClick) {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ export const HeroSectionLayout: React.FC<HeroSectionLayoutProps> = ({
|
||||||
onClick,
|
onClick,
|
||||||
className = "",
|
className = "",
|
||||||
renderer,
|
renderer,
|
||||||
|
onZoneComponentDrop,
|
||||||
|
onZoneClick,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
if (!layout.layoutConfig.heroSection) {
|
if (!layout.layoutConfig.heroSection) {
|
||||||
|
|
@ -56,7 +58,6 @@ export const HeroSectionLayout: React.FC<HeroSectionLayoutProps> = ({
|
||||||
onSelectComponent,
|
onSelectComponent,
|
||||||
isDesignMode: _isDesignMode,
|
isDesignMode: _isDesignMode,
|
||||||
allComponents,
|
allComponents,
|
||||||
onZoneClick,
|
|
||||||
onComponentDrop,
|
onComponentDrop,
|
||||||
onDragStart,
|
onDragStart,
|
||||||
onDragEnd,
|
onDragEnd,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ export const SplitLayout: React.FC<SplitLayoutProps> = ({
|
||||||
onClick,
|
onClick,
|
||||||
className = "",
|
className = "",
|
||||||
renderer,
|
renderer,
|
||||||
|
onZoneComponentDrop,
|
||||||
|
onZoneClick,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
if (!layout.layoutConfig.split) {
|
if (!layout.layoutConfig.split) {
|
||||||
|
|
@ -57,7 +59,6 @@ export const SplitLayout: React.FC<SplitLayoutProps> = ({
|
||||||
onSelectComponent,
|
onSelectComponent,
|
||||||
isDesignMode: _isDesignMode,
|
isDesignMode: _isDesignMode,
|
||||||
allComponents,
|
allComponents,
|
||||||
onZoneClick,
|
|
||||||
onComponentDrop,
|
onComponentDrop,
|
||||||
onDragStart,
|
onDragStart,
|
||||||
onDragEnd,
|
onDragEnd,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue