"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); const ratio = containerW > 0 ? containerW / canvasWidth : 1; const maxBottom = topLevel.reduce((max, c) => { const bottom = c.position.y + (c.size?.height || 40); return Math.max(max, bottom); }, 0); return (
0 ? `${maxBottom * ratio}px` : "200px" }} > {containerW > 0 && topLevel.map((component) => { const typeId = getComponentTypeId(component); return (
{renderComponent(component)}
); })}
); } export function ResponsiveGridRenderer({ components, canvasWidth, canvasHeight, renderComponent, }: ResponsiveGridRendererProps) { return ( ); } export default ResponsiveGridRenderer;