'use client'; import { useRef, useCallback } from 'react'; import { Database, X } from 'lucide-react'; import { PortHandle } from './PortHandle'; import { useControlMode } from './hooks/useControlMode'; interface TableNodeProps { tableName: string; label: string; /** 호환용 — 더 이상 사용 X (V3 컴팩트로 갈아엎으면서 이모지 폐기, Lucide Database 아이콘 고정) */ icon?: string; columns: Record[]; x: number; y: number; style?: React.CSSProperties; onMove?: (name: string, x: number, y: number) => void; /** 룰 노드 ID (PortHandle 연결용). 없으면 시각 카드만 (read-only) */ nodeId?: string; onPortDragStart?: (nodeId: string, port: string, e: React.MouseEvent) => void; onPortDragEnd?: (nodeId: string, port: string) => void; } /** * 테이블 카드 — V3RuleNode 와 일관된 컴팩트 디자인 * - 180px 폭, cyan top stripe, Lucide Database 아이콘 * - 한글 라벨 메인 + mono 영문 sub * - stats row: `{N} cols · {K} FK` * - 좌·우 edge 에 단일 port 1개씩 (테이블 단위 연결 — 컬럼은 노드 설정창 dropdown 에서) */ export function TableNode({ tableName, label, columns, x, y, style, onMove, nodeId, onPortDragStart, onPortDragEnd, }: TableNodeProps) { const nodeRef = useRef(null); const removeRuleNode = useControlMode((s) => s.removeRuleNode); const handleMouseDown = useCallback((e: React.MouseEvent) => { if (!onMove) return; const target = e.target as HTMLElement; if (target.closest('.ctrl-io-port, button')) return; e.preventDefault(); e.stopPropagation(); const sx = e.clientX, sy = e.clientY; const sl = x, st = y; const el = nodeRef.current; if (el) el.style.zIndex = '30'; let moved = false; const move = (ev: MouseEvent) => { const dx = ev.clientX - sx, dy = ev.clientY - sy; if (!moved && Math.abs(dx) + Math.abs(dy) < 2) return; moved = true; onMove(tableName, sl + dx, st + dy); }; const up = () => { if (el) el.style.zIndex = '20'; document.removeEventListener('mousemove', move); document.removeEventListener('mouseup', up); }; document.addEventListener('mousemove', move); document.addEventListener('mouseup', up); }, [onMove, tableName, x, y]); // stats const totalCols = columns?.length ?? 0; const fkCount = (columns ?? []).filter((c) => c.mark === 'FK' || c.type === 'entity').length; const pkCount = (columns ?? []).filter((c) => c.pk).length; const hasKoLabel = label && label !== tableName; return (
{/* cyan top stripe (V3RuleNode cat-stripe 와 일관) */}
{hasKoLabel ? label : tableName}
{hasKoLabel &&
{tableName}
}
{nodeId && ( )}
{totalCols} cols {pkCount > 0 && · {pkCount} PK} {fkCount > 0 && · {fkCount} FK}
{/* 좌·우 단일 port — 테이블 단위 연결 (컬럼 선택은 노드 설정창 dropdown) */} {nodeId && ( <>
)}
); }