diff --git a/frontend/components/screen/ScreenDesigner.tsx b/frontend/components/screen/ScreenDesigner.tsx index c10e9bff..c8941515 100644 --- a/frontend/components/screen/ScreenDesigner.tsx +++ b/frontend/components/screen/ScreenDesigner.tsx @@ -3568,8 +3568,104 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD ); // 드래그 종료 - const endDrag = useCallback(() => { + const endDrag = useCallback((mouseEvent?: MouseEvent) => { if (dragState.isDragging && dragState.draggedComponent) { + // 🎯 탭 컨테이너로의 드롭 처리 (기존 컴포넌트 이동) + if (mouseEvent) { + const dropTarget = document.elementFromPoint(mouseEvent.clientX, mouseEvent.clientY) as HTMLElement; + const tabsContainer = dropTarget?.closest('[data-tabs-container="true"]'); + + if (tabsContainer) { + const containerId = tabsContainer.getAttribute("data-component-id"); + const activeTabId = tabsContainer.getAttribute("data-active-tab-id"); + + if (containerId && activeTabId) { + const targetComponent = layout.components.find((c) => c.id === containerId); + const compType = (targetComponent as any)?.componentType; + + // 자기 자신을 자신에게 드롭하는 것 방지 + if (targetComponent && + (compType === "tabs-widget" || compType === "v2-tabs-widget") && + dragState.draggedComponent !== containerId) { + + const draggedComponent = layout.components.find((c) => c.id === dragState.draggedComponent); + if (draggedComponent) { + const currentConfig = (targetComponent as any).componentConfig || {}; + const tabs = currentConfig.tabs || []; + + // 탭 컨텐츠 영역 기준 드롭 위치 계산 + const tabContentRect = tabsContainer.getBoundingClientRect(); + const dropX = (mouseEvent.clientX - tabContentRect.left) / zoomLevel; + const dropY = (mouseEvent.clientY - tabContentRect.top) / zoomLevel; + + // 기존 컴포넌트를 탭 내부 컴포넌트로 변환 + const newTabComponent = { + id: `tab_comp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, + componentType: (draggedComponent as any).componentType || draggedComponent.type, + label: (draggedComponent as any).label || "컴포넌트", + position: { x: Math.max(0, dropX), y: Math.max(0, dropY) }, + size: draggedComponent.size || { width: 200, height: 100 }, + componentConfig: (draggedComponent as any).componentConfig || {}, + style: (draggedComponent as any).style || {}, + }; + + // 해당 탭에 컴포넌트 추가 + const updatedTabs = tabs.map((tab: any) => { + if (tab.id === activeTabId) { + return { + ...tab, + components: [...(tab.components || []), newTabComponent], + }; + } + return tab; + }); + + // 탭 컴포넌트 업데이트 + 원래 컴포넌트 캔버스에서 제거 + const newLayout = { + ...layout, + components: layout.components + .filter((c) => c.id !== dragState.draggedComponent) // 캔버스에서 제거 + .map((c) => { + if (c.id === containerId) { + return { + ...c, + componentConfig: { + ...currentConfig, + tabs: updatedTabs, + }, + }; + } + return c; + }), + }; + + setLayout(newLayout); + saveToHistory(newLayout); + setSelectedComponent(null); + toast.success("컴포넌트가 탭으로 이동되었습니다"); + + // 드래그 상태 초기화 후 종료 + setDragState({ + isDragging: false, + draggedComponent: null, + draggedComponents: [], + originalPosition: { x: 0, y: 0, z: 1 }, + currentPosition: { x: 0, y: 0, z: 1 }, + grabOffset: { x: 0, y: 0 }, + justFinishedDrag: true, + }); + + setTimeout(() => { + setDragState((prev) => ({ ...prev, justFinishedDrag: false })); + }, 100); + + return; // 탭으로 이동 완료, 일반 드래그 종료 로직 스킵 + } + } + } + } + } + // 주 드래그 컴포넌트의 최종 위치 계산 const draggedComponent = layout.components.find((c) => c.id === dragState.draggedComponent); let finalPosition = dragState.currentPosition; @@ -4445,12 +4541,12 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD } }; - const handleMouseUp = () => { + const handleMouseUp = (e: MouseEvent) => { if (dragState.isDragging) { if (animationFrameId) { cancelAnimationFrame(animationFrameId); } - endDrag(); + endDrag(e); } else if (selectionDrag.isSelecting) { endSelectionDrag(); }