import React, { useState, useRef, useCallback } from "react"; import { Upload, FileCode, Plus, Trash2, AlertCircle, CheckCircle2, Settings2, } from "lucide-react"; import { parseYAML, validateYAML, toYAML, PROTOCOLS, DEFAULT_YAML } from "../utils/yamlUtils"; export default function YAMLForm({ onSpecChange, validationErrors }) { const [yamlText, setYamlText] = useState(DEFAULT_YAML); const [parsed, setParsed] = useState(() => parseYAML(DEFAULT_YAML)); const [mode, setMode] = useState("editor"); // editor | parsed | split const [activeTab, setActiveTab] = useState("spec"); // spec | signals | registers const fileRef = useRef(null); const handleChange = useCallback( (text) => { setYamlText(text); try { const obj = parseYAML(text); setParsed(obj); onSpecChange(obj); } catch { // keep previous parsed state } }, [onSpecChange] ); const handleFileUpload = useCallback( (e) => { const file = e.target.files?.[0]; if (!file) return; const reader = new FileReader(); reader.onload = (ev) => handleChange(ev.target.result); reader.readAsText(file); }, [handleChange] ); const handlePasteExample = useCallback(() => { handleChange(DEFAULT_YAML); }, [handleChange]); const errors = validateYAML(yamlText); // ── Signal / Register editors ──────────────────────────────────── const updateInterface = (idx, field, value) => { const ifaces = [...(parsed.interfaces || [])]; ifaces[idx] = { ...ifaces[idx], [field]: value }; const updated = { ...parsed, interfaces: ifaces }; setParsed(updated); handleChange(toYAML(updated)); }; const addSignal = (ifaceIdx) => { const ifaces = [...(parsed.interfaces || [])]; const existing = Array.isArray(ifaces[ifaceIdx]?.signals) ? ifaces[ifaceIdx].signals : []; const signals = [...existing, { name: "", direction: "input", width: 1 }]; ifaces[ifaceIdx] = { ...ifaces[ifaceIdx], signals }; const updated = { ...parsed, interfaces: ifaces }; setParsed(updated); handleChange(toYAML(updated)); }; const updateSignal = (ifaceIdx, sigIdx, field, value) => { const ifaces = [...(parsed.interfaces || [])]; const existing = Array.isArray(ifaces[ifaceIdx]?.signals) ? ifaces[ifaceIdx].signals : []; const signals = [...existing]; signals[sigIdx] = { ...signals[sigIdx], [field]: value }; ifaces[ifaceIdx] = { ...ifaces[ifaceIdx], signals }; const updated = { ...parsed, interfaces: ifaces }; setParsed(updated); handleChange(toYAML(updated)); }; const removeSignal = (ifaceIdx, sigIdx) => { const ifaces = [...(parsed.interfaces || [])]; const sigs = Array.isArray(ifaces[ifaceIdx].signals) ? ifaces[ifaceIdx].signals : []; ifaces[ifaceIdx] = { ...ifaces[ifaceIdx], signals: sigs.filter((_, i) => i !== sigIdx), }; const updated = { ...parsed, interfaces: ifaces }; setParsed(updated); handleChange(toYAML(updated)); }; const addRegister = () => { const regs = [...(parsed.registers || []), { name: "", address: "0x00", access: "rw", fields: [] }]; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; const updateRegister = (idx, field, value) => { const regs = [...(parsed.registers || [])]; regs[idx] = { ...regs[idx], [field]: value }; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; const removeRegister = (idx) => { const updated = { ...parsed, registers: parsed.registers.filter((_, i) => i !== idx) }; setParsed(updated); handleChange(toYAML(updated)); }; const addField = (regIdx) => { const regs = [...(parsed.registers || [])]; const fields = [...(regs[regIdx]?.fields || []), { name: "", bits: "0", description: "" }]; regs[regIdx] = { ...regs[regIdx], fields }; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; const updateField = (regIdx, fldIdx, field, value) => { const regs = [...(parsed.registers || [])]; const fields = [...(regs[regIdx]?.fields || [])]; fields[fldIdx] = { ...fields[fldIdx], [field]: value }; regs[regIdx] = { ...regs[regIdx], fields }; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; const removeField = (regIdx, fldIdx) => { const regs = [...(parsed.registers || [])]; regs[regIdx] = { ...regs[regIdx], fields: regs[regIdx].fields.filter((_, i) => i !== fldIdx), }; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; return (

Design Specification

{/* Toolbar */}
{["spec", "signals", "registers"].map((t) => ( ))}
{/* Validation status */} {errors.length > 0 && (
{errors.map((e, i) => (

{e}

))}
)} {errors.length === 0 && yamlText.trim() && (
YAML syntax valid
)} {/* ── Spec tab ─────────────────────────────────── */} {activeTab === "spec" && (
{ const updated = { ...parsed, design_name: e.target.value }; setParsed(updated); handleChange(toYAML(updated)); }} placeholder="uart16550" />
{ const updated = { ...parsed, version: e.target.value }; setParsed(updated); handleChange(toYAML(updated)); }} placeholder="1.5" />
{ const updated = { ...parsed, vendor: e.target.value }; setParsed(updated); handleChange(toYAML(updated)); }} placeholder="DV Automation" />