import React from 'react'; import { ContextMenu } from './ContextMenu'; import { type MapContextMenuEvent, type EditMode, type SimulationResult, type SelectionTarget } from './types'; import { type NetworkModel, type InpNode } from './inpModel'; import { type CRS } from './crs'; import { type MapFocusRequest } from './Map'; export interface MapContextMenuProps { contextMenu: MapContextMenuEvent; setContextMenu: React.Dispatch>; appMode: 'explore' | 'edit' | 'result'; setAppMode: React.Dispatch>; setEditMode: React.Dispatch>; networkModel: NetworkModel | null; wasmResult: SimulationResult | null; crs: CRS; setSelectedTarget: React.Dispatch>; setActiveTab: React.Dispatch>; requestMapFocus: (request: Omit) => void; showToast: (msg: string) => void; handleAddNodeAtCoords: (x: number, y: number, nodeType?: InpNode['type']) => void; handleCopyText: (text: string, label: string) => void; handleZoomToLayer: (layerId: string) => void; handleDeleteSelected: () => void; handleRecalculateLength: (pipeId: string) => void; handleReversePipe: (pipeId: string) => void; handleSplitPipe: (pipeId: string) => void; } /** Right-click menu on the map (node/link/empty-space actions). */ export const MapContextMenu: React.FC = ({ contextMenu, setContextMenu, appMode, setAppMode, setEditMode, networkModel, wasmResult, crs, setSelectedTarget, setActiveTab, requestMapFocus, showToast, handleAddNodeAtCoords, handleCopyText, handleZoomToLayer, handleDeleteSelected, handleRecalculateLength, handleReversePipe, handleSplitPipe, }) => ( setContextMenu(null)} onCopyText={handleCopyText} onAddNodeAtCoords={(x, y) => { handleAddNodeAtCoords(x, y, 'JUNCTION'); setContextMenu(null); }} onFitBounds={() => { showToast('전체 화면을 표시합니다.'); }} onPanTo={(lngLat) => { requestMapFocus({ lngLat, zoom: 17 }); showToast(`좌표 (${lngLat[0].toFixed(4)}, ${lngLat[1].toFixed(4)})로 이동했습니다.`); }} onInspectTarget={(target) => { if (target.type === 'node' || target.type === 'link') { setSelectedTarget(target); } setActiveTab('inspector'); }} onViewResults={(target) => { setSelectedTarget(target); setActiveTab('results'); }} onStartPipeFromNode={(nodeId) => { if (appMode !== 'edit') setAppMode('edit'); setEditMode('add-pipe'); setSelectedTarget({ type: 'node', id: nodeId }); }} onSplitPipe={handleSplitPipe} onSelectConnectedLinks={(nodeId) => { if (!networkModel) return; const connectedPipes = Object.values(networkModel.pipes).filter( (p) => p.node1 === nodeId || p.node2 === nodeId ); if (connectedPipes.length > 0) { setSelectedTarget({ type: 'link', id: connectedPipes[0].id }); setActiveTab('inspector'); showToast(`연결 관로 [${connectedPipes[0].id}] 선택됨 (총 ${connectedPipes.length}개 관로)`); } }} onSelectConnectedNodes={(pipeId) => { if (!networkModel) return; const pipe = networkModel.pipes[pipeId]; if (pipe) { setSelectedTarget({ type: 'node', id: pipe.node1 }); setActiveTab('inspector'); showToast(`시작 절점 [${pipe.node1}] 선택됨 (끝 절점: ${pipe.node2})`); } }} onCalculatePipeLength={handleRecalculateLength} onReversePipe={handleReversePipe} onDeleteNode={handleDeleteSelected} onDeletePipe={handleDeleteSelected} onZoomToLayer={handleZoomToLayer} canRunResults={!!wasmResult} /> );