@@ -41,15 +41,14 @@ interface NodeTemplate {
4141 inputs : string [ ] ;
4242 outputs : string [ ] ;
4343 content ?: m . Children ;
44- allInputsLeft ?: boolean ;
4544}
4645
4746interface NodeGraphDemoAttrs {
4847 readonly titleBars ?: boolean ;
4948 readonly accentBars ?: boolean ;
5049 readonly allInputsLeft ?: boolean ;
5150 readonly allOutputsRight ?: boolean ;
52- readonly multiselect ?: boolean ;
51+ readonly colors ?: boolean ;
5352}
5453
5554export function NodeGraphDemo ( ) : m . Component < NodeGraphDemoAttrs > {
@@ -190,7 +189,6 @@ export function NodeGraphDemo(): m.Component<NodeGraphDemoAttrs> {
190189 join : {
191190 inputs : [ 'Left' , 'Right' ] ,
192191 outputs : [ 'Output' ] ,
193- allInputsLeft : true ,
194192 content : m (
195193 '' ,
196194 { style : { display : 'flex' , flexDirection : 'column' , gap : '4px' } } ,
@@ -231,89 +229,97 @@ export function NodeGraphDemo(): m.Component<NodeGraphDemoAttrs> {
231229 return Array . from ( modelNodes . keys ( ) ) . filter ( ( id ) => ! referenced . has ( id ) ) ;
232230 }
233231
234- // Render model state into NodeGraph nodes
235- function renderNodes ( ) : Node [ ] {
236- const rootIds = getRootNodeIds ( ) ;
237- return rootIds
238- . map ( ( id ) => {
239- const model = modelNodes . get ( id ) ;
240- if ( ! model ) return null ;
241- return renderNodeChain ( model ) ;
242- } )
243- . filter ( ( n ) : n is Node => n !== null ) ;
244- }
245-
246- // Render a model node and its chain
247- function renderNodeChain ( model : ModelNode ) : Node {
248- const template = nodeTemplates [ model . type ] ;
249- const hasNext = model . nextId !== undefined ;
250- const nextModel = hasNext ? modelNodes . get ( model . nextId ! ) : undefined ;
251- const allInputsLeft = template . allInputsLeft ?? false ;
252-
253- return {
254- id : model . id ,
255- x : model . x ,
256- y : model . y ,
257- inputs : template . inputs ,
258- outputs : template . outputs ,
259- content : template . content ,
260- next : nextModel ? renderChildNode ( nextModel ) : undefined ,
261- allInputsLeft,
262- accentBar : true ,
263- hue : nodeHues [ model . type ] ,
264- addMenuItems : [
265- m ( MenuItem , {
266- label : 'Select' ,
267- icon : 'filter_alt' ,
268- onclick : ( ) => addNode ( 'select' , model . id ) ,
269- } ) ,
270- m ( MenuItem , {
271- label : 'Filter' ,
272- icon : 'filter_list' ,
273- onclick : ( ) => addNode ( 'filter' , model . id ) ,
274- } ) ,
275- ] ,
276- } ;
277- }
232+ const connections : Connection [ ] = [ ] ;
278233
279- // Render child node (keep all ports visible)
280- function renderChildNode ( model : ModelNode ) : Omit < Node , 'x' | 'y' > {
281- const template = nodeTemplates [ model . type ] ;
282- const hasNext = model . nextId !== undefined ;
283- const nextModel = hasNext ? modelNodes . get ( model . nextId ! ) : undefined ;
234+ return {
235+ view : ( { attrs} : m . Vnode < NodeGraphDemoAttrs > ) => {
236+ // Render a model node and its chain
237+ function renderNodeChain ( model : ModelNode ) : Node {
238+ const template = nodeTemplates [ model . type ] ;
239+ const hasNext = model . nextId !== undefined ;
240+ const nextModel = hasNext ? modelNodes . get ( model . nextId ! ) : undefined ;
241+
242+ return {
243+ id : model . id ,
244+ x : model . x ,
245+ y : model . y ,
246+ inputs : template . inputs ,
247+ outputs : template . outputs ,
248+ content : template . content ,
249+ next : nextModel ? renderChildNode ( nextModel ) : undefined ,
250+ allInputsLeft : attrs . allInputsLeft ,
251+ allOutputsRight : attrs . allOutputsRight ,
252+ accentBar : attrs . accentBars ,
253+ titleBar : attrs . titleBars
254+ ? { title : model . type . toUpperCase ( ) }
255+ : undefined ,
256+ hue : attrs . colors ? nodeHues [ model . type ] : undefined ,
257+ addMenuItems : [
258+ m ( MenuItem , {
259+ label : 'Select' ,
260+ icon : 'filter_alt' ,
261+ onclick : ( ) => addNode ( 'select' , model . id ) ,
262+ } ) ,
263+ m ( MenuItem , {
264+ label : 'Filter' ,
265+ icon : 'filter_list' ,
266+ onclick : ( ) => addNode ( 'filter' , model . id ) ,
267+ } ) ,
268+ ] ,
269+ } ;
270+ }
284271
285- return {
286- id : model . id ,
287- inputs : template . inputs ,
288- outputs : template . outputs ,
289- content : template . content ,
290- next : nextModel ? renderChildNode ( nextModel ) : undefined ,
291- accentBar : true ,
292- hue : nodeHues [ model . type ] ,
293- addMenuItems : [
294- m ( MenuItem , {
295- label : 'Select' ,
296- icon : 'filter_alt' ,
297- onclick : ( ) => addNode ( 'select' , model . id ) ,
298- } ) ,
299- m ( MenuItem , {
300- label : 'Filter' ,
301- icon : 'filter_list' ,
302- onclick : ( ) => addNode ( 'filter' , model . id ) ,
303- } ) ,
304- m ( MenuItem , {
305- label : 'Join' ,
306- icon : 'join' ,
307- onclick : ( ) => addNode ( 'join' , model . id ) ,
308- } ) ,
309- ] ,
310- } ;
311- }
272+ // Render child node (keep all ports visible)
273+ function renderChildNode ( model : ModelNode ) : Omit < Node , 'x' | 'y' > {
274+ const template = nodeTemplates [ model . type ] ;
275+ const hasNext = model . nextId !== undefined ;
276+ const nextModel = hasNext ? modelNodes . get ( model . nextId ! ) : undefined ;
277+
278+ return {
279+ id : model . id ,
280+ inputs : template . inputs ,
281+ outputs : template . outputs ,
282+ content : template . content ,
283+ next : nextModel ? renderChildNode ( nextModel ) : undefined ,
284+ allInputsLeft : attrs . allInputsLeft ,
285+ allOutputsRight : attrs . allOutputsRight ,
286+ accentBar : attrs . accentBars ,
287+ titleBar : attrs . titleBars
288+ ? { title : model . type . toUpperCase ( ) }
289+ : undefined ,
290+ hue : attrs . colors ? nodeHues [ model . type ] : undefined ,
291+ addMenuItems : [
292+ m ( MenuItem , {
293+ label : 'Select' ,
294+ icon : 'filter_alt' ,
295+ onclick : ( ) => addNode ( 'select' , model . id ) ,
296+ } ) ,
297+ m ( MenuItem , {
298+ label : 'Filter' ,
299+ icon : 'filter_list' ,
300+ onclick : ( ) => addNode ( 'filter' , model . id ) ,
301+ } ) ,
302+ m ( MenuItem , {
303+ label : 'Join' ,
304+ icon : 'join' ,
305+ onclick : ( ) => addNode ( 'join' , model . id ) ,
306+ } ) ,
307+ ] ,
308+ } ;
309+ }
312310
313- const connections : Connection [ ] = [ ] ;
311+ // Render model state into NodeGraph nodes
312+ function renderNodes ( ) : Node [ ] {
313+ const rootIds = getRootNodeIds ( ) ;
314+ return rootIds
315+ . map ( ( id ) => {
316+ const model = modelNodes . get ( id ) ;
317+ if ( ! model ) return null ;
318+ return renderNodeChain ( model ) ;
319+ } )
320+ . filter ( ( n ) : n is Node => n !== null ) ;
321+ }
314322
315- return {
316- view : ( ) => {
317323 return m ( 'div' , [
318324 // Add Node button
319325 m (
0 commit comments