import { h } from 'preact'; import { useEffect, useRef } from 'preact/hooks'; import type { SignalRef, SignalMeta } from './lib/types'; import { getMetaStore } from './lib/stores'; import { useState } from 'preact/hooks'; interface Props { visible: boolean; x: number; y: number; signal: SignalRef | null; onClose: () => void; onInfo?: () => void; onPlot?: () => void; } export default function ContextMenu({ visible, x, y, signal, onClose, onInfo, onPlot }: Props) { const [meta, setMeta] = useState(null); const menuRef = useRef(null); useEffect(() => { if (!signal) { setMeta(null); return; } const unsub = getMetaStore(signal).subscribe(setMeta); return unsub; }, [signal?.ds, signal?.name]); useEffect(() => { if (!visible) return; function handleClick(e: MouseEvent) { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { onClose(); } } document.addEventListener('mousedown', handleClick); return () => document.removeEventListener('mousedown', handleClick); }, [visible, onClose]); if (!visible) return null; function copySignalName() { if (signal) navigator.clipboard.writeText(signal.name).catch(() => {}); onClose(); } function openInfo() { onClose(); onInfo?.(); } function openPlot() { onClose(); onPlot?.(); } function exportCSV() { // Phase 5+: export CSV data onClose(); } return (
{signal ? (
{signal.ds} / {signal.name}
{meta && (
{meta.type}{meta.unit ? ` [${meta.unit}]` : ''}
)}
) : ( )}
); }