From cb4e81beb2e24e5150a021e644bd9de62f548299 Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Wed, 24 Jun 2026 13:59:18 +0200 Subject: [PATCH] fix(editor): array local-variable support in signal-tree pane The signal-tree pane (edit mode) has its own inline "add local variable" form, separate from the Logic-tab LocalVars form that gained array support in the array-locals feature. This second entry point was missed, so the type dropdown there only offered number/bool/string. Mirror the LogicEditor form: add the array type option plus elem/sizing/capacity selects and a JSON-validated initial value. Co-Authored-By: Claude Opus 4.6 --- web/src/SignalTree.tsx | 79 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/web/src/SignalTree.tsx b/web/src/SignalTree.tsx index dd0f69a..37b6b68 100644 --- a/web/src/SignalTree.tsx +++ b/web/src/SignalTree.tsx @@ -117,17 +117,48 @@ export default function SignalTree({ onDragStart, width, panelId, statevars, onS const [showAddLocal, setShowAddLocal] = useState(false); const [localOpen, setLocalOpen] = useState(true); const [lvName, setLvName] = useState(''); - const [lvType, setLvType] = useState<'number' | 'bool' | 'string'>('number'); + const [lvType, setLvType] = useState<'number' | 'bool' | 'string' | 'array'>('number'); const [lvInitial, setLvInitial] = useState('0'); + // array-specific fields (mirror LogicEditor LocalVars) + const [lvElem, setLvElem] = useState<'number' | 'bool' | 'array'>('number'); + const [lvSizing, setLvSizing] = useState<'dynamic' | 'capped' | 'fixed'>('dynamic'); + const [lvCapacity, setLvCapacity] = useState('100'); + const [lvJsonErr, setLvJsonErr] = useState(''); + + function handleLvTypeChange(t: 'number' | 'bool' | 'string' | 'array') { + setLvType(t); + setLvInitial(t === 'array' ? '[]' : t === 'bool' ? 'false' : t === 'string' ? '' : '0'); + setLvJsonErr(''); + } + + function handleLvInitialChange(v: string) { + setLvInitial(v); + if (lvType === 'array') { + try { JSON.parse(v); setLvJsonErr(''); } + catch (e: any) { setLvJsonErr(e.message); } + } + } function addLocal() { const name = lvName.trim(); if (!name || !onStateVarsChange) return; + if (lvType === 'array' && lvJsonErr) return; + const base: StateVar = { name, type: lvType, initial: lvInitial }; + if (lvType === 'array') { + base.elem = lvElem; + base.sizing = lvSizing; + if (lvSizing !== 'dynamic') base.capacity = parseInt(lvCapacity, 10) || 100; + } const next = (statevars ?? []).filter(v => v.name !== name); - next.push({ name, type: lvType, initial: lvInitial }); + next.push(base); onStateVarsChange(next); setLvName(''); setLvInitial('0'); + setLvType('number'); + setLvElem('number'); + setLvSizing('dynamic'); + setLvCapacity('100'); + setLvJsonErr(''); setShowAddLocal(false); } @@ -324,20 +355,56 @@ export default function SignalTree({ onDragStart, width, panelId, statevars, onS class="prop-select" style="font-size: 0.7rem; height: 1.6rem; padding: 0 4px;" value={lvType} - onChange={(e) => setLvType((e.target as HTMLSelectElement).value as any)} + onChange={(e) => handleLvTypeChange((e.target as HTMLSelectElement).value as any)} > + + {lvType === 'array' && ( + + + + {lvSizing !== 'dynamic' && ( + setLvCapacity((e.target as HTMLInputElement).value)} + /> + )} + + )} setLvInitial((e.target as HTMLInputElement).value)} + onInput={(e) => handleLvInitialChange((e.target as HTMLInputElement).value)} onKeyDown={(e: KeyboardEvent) => { if (e.key === 'Enter') addLocal(); }} /> + {lvJsonErr &&

{lvJsonErr}

}