import { useRef, useState, useEffect } from 'react' import { createPortal } from 'react-dom' import { useEngineDesign } from '../hooks/useEngineDesign.js' import { PropellantModal } from '../components/PropellantModal.jsx' import { exportEngineJSON, exportEngineOdt, parseEngineImport, downloadBlob, } from '../engine/engineExportImport.js' import DesignSection from '../components/engine/DesignSection.jsx' import EngineModel3D from '../components/engine/EngineModel3D.jsx' import NozzleDiagram from '../components/engine/NozzleDiagram.jsx' import PerformanceCharts from '../components/engine/PerformanceCharts.jsx' import ErrorBoundary from '../components/ErrorBoundary.jsx' import { formatValue } from '../engine/format.js' import { getUnitsForFamily } from '../engine/units.js' import { ENGINE_FIELD_INFO } from '../engine/engineFieldInfo.js' import { ABLATIVE_MATERIALS, STRUCTURAL_MATERIALS } from '../engine/knowledgebaseData.js' /* ── Info popup ───────────────────────────────────────────────────── */ function InfoPopup({ infoKey, anchorRef, onClose }) { const popupRef = useRef(null) const info = ENGINE_FIELD_INFO[infoKey] const [pos, setPos] = useState({ top: 0, left: 0 }) useEffect(() => { if (anchorRef.current) { const r = anchorRef.current.getBoundingClientRect() setPos({ top: r.bottom + 6, left: Math.min(r.left, window.innerWidth - 230), }) } }, [anchorRef]) useEffect(() => { function onKey(e) { if (e.key === 'Escape') onClose() } function onDown(e) { if (!popupRef.current?.contains(e.target) && !anchorRef.current?.contains(e.target)) { onClose() } } document.addEventListener('keydown', onKey) document.addEventListener('mousedown', onDown) return () => { document.removeEventListener('keydown', onKey) document.removeEventListener('mousedown', onDown) } }, [onClose, anchorRef]) if (!info) return null return createPortal(
{info.name}
{info.description}
{info.higher &&↑ {info.higher}
} {info.lower &&↓ {info.lower}
}{cr.note}
)} > ) : (—
)}—
)}—
)}