/** * Canvas host: mounts the JointJS paper via EditorController and accepts * palette drops. */ import { useEffect, useRef } from 'react'; import { EditorController } from '../editor/paper'; import { PALETTE_MIME } from './Palette'; import { getState, setState, bumpGraphVersion, applySimulationResult } from '../state/store'; interface CanvasProps { onReady(controller: EditorController): void; } export function Canvas({ onReady }: CanvasProps) { const hostRef = useRef(null); const controllerRef = useRef(null); useEffect(() => { const host = hostRef.current; if (!host || controllerRef.current) return; const controller = new EditorController(host, getState().config, { onSelectionChange: (selection) => setState({ selection }), onGraphChange: () => bumpGraphVersion(), onHistoryChange: (canUndo, canRedo) => setState({ canUndo, canRedo }), onSimulationChange: (running, result) => applySimulationResult(running, result), }); controllerRef.current = controller; onReady(controller); return () => { controller.dispose(); controllerRef.current = null; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return (
{ if (e.dataTransfer.types.includes(PALETTE_MIME)) { e.preventDefault(); e.dataTransfer.dropEffect = 'copy'; } }} onDrop={(e) => { const typeId = e.dataTransfer.getData(PALETTE_MIME); const controller = controllerRef.current; if (!typeId || !controller) return; e.preventDefault(); const p = controller.clientToLocal(e.clientX, e.clientY); controller.addNode(typeId, p.x, p.y); }} /> ); }