Files
uopi/web/src/ContextMenu.tsx
T
2026-05-04 21:13:36 +02:00

87 lines
2.3 KiB
TypeScript

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<SignalMeta | null>(null);
const menuRef = useRef<HTMLDivElement>(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 (
<div
class="ctx-menu"
ref={menuRef}
style={`left:${x}px;top:${y}px;`}
>
{signal ? (
<div>
<div class="ctx-signal-info">
<div>{signal.ds} / {signal.name}</div>
{meta && (
<div>{meta.type}{meta.unit ? ` [${meta.unit}]` : ''}</div>
)}
</div>
<div class="ctx-divider" />
<button class="ctx-item" onClick={openInfo}>Signal info</button>
<button class="ctx-item" onClick={openPlot}>Plot</button>
<div class="ctx-divider" />
<button class="ctx-item" onClick={copySignalName}>Copy signal name</button>
<button class="ctx-item" onClick={exportCSV}>Export data to CSV</button>
</div>
) : (
<button class="ctx-item" onClick={onClose}>Close</button>
)}
</div>
);
}