@@ -11,7 +11,6 @@ import { NodeEditor } from './components/Editor';
1111import { DebugPanel } from './components/Debug' ;
1212import { InfoPanel } from './components/Info' ;
1313import { CanvasPanel } from './components/Canvases/CanvasPanel' ;
14- import { ButtonsPanel } from './components/Buttons' ;
1514import { generateId } from './utils/id' ;
1615import { storage } from './utils/storage' ;
1716import { nodeRegistry } from './nodes' ;
@@ -27,7 +26,7 @@ function AppContent() {
2726 const { state : editor , dispatch : editorDispatch } = useEditor ( ) ;
2827 const { dispatch : flowDispatch } = useFlows ( ) ;
2928 const { messages, downloads } = useDebug ( ) ;
30- const { inject : runtimeInject , callMainThread, isRunning, isReady, deploy, hasCanvasNodes, hasButtonsNodes } = useRuntime ( ) ;
29+ const { inject : runtimeInject , callMainThread, isRunning, isReady, deploy, hasCanvasNodes, emitNodeEvent } = useRuntime ( ) ;
3130 const { state : flowState } = useFlows ( ) ;
3231 const { addNode, deleteSelected, nodes } = useNodes ( ) ;
3332
@@ -274,8 +273,31 @@ function AppContent() {
274273 }
275274 } , [ isRunning , callMainThread ] ) ;
276275
277- // Get undo/redo from flow context
278- const { undo, redo, canUndo, canRedo } = useFlows ( ) ;
276+ // Get undo/redo and runtime update from flow context
277+ const { undo, redo, canUndo, canRedo, updateNodeRuntime } = useFlows ( ) ;
278+
279+ // Handle interactive node events (buttons, sliders, etc.)
280+ const handleNodeInteraction = useCallback ( ( nodeId , eventName , data ) => {
281+ // Update visual state if requested (for sliders, buttons, etc.)
282+ if ( data ?. updateValue ) {
283+ const runtimeProps = { } ;
284+ if ( data . value !== undefined ) {
285+ runtimeProps . _currentValue = data . value ;
286+ }
287+ if ( data . activeButton !== undefined ) {
288+ runtimeProps . _activeButton = data . activeButton ;
289+ }
290+ if ( Object . keys ( runtimeProps ) . length > 0 ) {
291+ updateNodeRuntime ( nodeId , runtimeProps ) ;
292+ }
293+ }
294+
295+ if ( ! isRunning ) {
296+ logger . warn ( 'Runtime not running - deploy first' ) ;
297+ return ;
298+ }
299+ emitNodeEvent ( nodeId , eventName , data ) ;
300+ } , [ isRunning , emitNodeEvent , updateNodeRuntime ] ) ;
279301
280302 // Copy selected nodes
281303 const copyNodes = useCallback ( ( ) => {
@@ -422,9 +444,8 @@ function AppContent() {
422444 // Compute effective tab - fall back to debug if selected tab is unavailable
423445 const effectiveTab = useMemo ( ( ) => {
424446 if ( sidebarTab === 'canvases' && ! hasCanvasNodes ) return 'debug' ;
425- if ( sidebarTab === 'buttons' && ! hasButtonsNodes ) return 'debug' ;
426447 return sidebarTab ;
427- } , [ sidebarTab , hasCanvasNodes , hasButtonsNodes ] ) ;
448+ } , [ sidebarTab , hasCanvasNodes ] ) ;
428449
429450 return (
430451 < div className = "app" >
@@ -436,7 +457,7 @@ function AppContent() {
436457 onDrop = { handleDrop }
437458 onDragOver = { handleDragOver }
438459 >
439- < Canvas onEditNode = { handleEditNode } onInject = { handleInject } onFileDrop = { handleFileDrop } />
460+ < Canvas onEditNode = { handleEditNode } onInject = { handleInject } onFileDrop = { handleFileDrop } onNodeInteraction = { handleNodeInteraction } />
440461 </ div >
441462 < div
442463 className = { `resize-handle ${ isResizing ? 'resizing' : '' } ` }
@@ -468,14 +489,6 @@ function AppContent() {
468489 Canvases
469490 </ button >
470491 ) }
471- { hasButtonsNodes && (
472- < button
473- className = { `sidebar-tab ${ effectiveTab === 'buttons' ? 'active' : '' } ` }
474- onClick = { ( ) => setSidebarTab ( 'buttons' ) }
475- >
476- Buttons
477- </ button >
478- ) }
479492 </ div >
480493 { effectiveTab === 'debug' && < DebugPanel /> }
481494 { effectiveTab === 'info' && < InfoPanel onEditNode = { handleEditNode } /> }
@@ -485,7 +498,6 @@ function AppContent() {
485498 < CanvasPanel />
486499 </ div >
487500 ) }
488- { hasButtonsNodes && effectiveTab === 'buttons' && < ButtonsPanel /> }
489501 </ div >
490502
491503 { /* Node editor dialog */ }
0 commit comments