"use client"; import React, { useRef, useState, useEffect } from "react"; import { ComponentData } from "@/types/screen"; interface ResponsiveGridRendererProps { components: ComponentData[]; canvasWidth: number; canvasHeight: number; renderComponent: (component: ComponentData) => React.ReactNode; } function getComponentTypeId(component: ComponentData): string { const direct = (component as any).componentType || (component as any).widgetType; if (direct) return direct; const url = (component as any).url; if (url && typeof url === "string") { const parts = url.split("/"); return parts[parts.length - 1]; } return component.type || ""; } /** * 디자이너 절대좌표를 캔버스 대비 비율(%)로 변환하여 렌더링. * 가로: 컨테이너 너비 대비 % → 반응형 스케일 * 세로: 컨테이너 높이 대비 % → 뷰포트에 맞게 자동 조절 */ function ProportionalRenderer({ components, canvasWidth, canvasHeight, renderComponent, }: ResponsiveGridRendererProps) { const containerRef = useRef(null); const [containerW, setContainerW] = useState(0); useEffect(() => { const el = containerRef.current; if (!el) return; const ro = new ResizeObserver((entries) => { const w = entries[0]?.contentRect.width; if (w && w > 0) setContainerW(w); }); ro.observe(el); return () => ro.disconnect(); }, []); const topLevel = components.filter((c) => !c.parentId); return (
{containerW > 0 && topLevel.map((component) => { const typeId = getComponentTypeId(component); return (
{renderComponent(component)}
); })}
); } export function ResponsiveGridRenderer({ components, canvasWidth, canvasHeight, renderComponent, }: ResponsiveGridRendererProps) { return ( ); } export default ResponsiveGridRenderer;