@@ -13,7 +13,18 @@ import type { InputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
13
13
import { useNodeDefStore } from '@/stores/nodeDefStore'
14
14
import type { WidgetValue } from '@/types/simplifiedWidget'
15
15
16
- import type { LGraph , LGraphNode } from '../../lib/litegraph/src/litegraph'
16
+ import type {
17
+ LGraph ,
18
+ LGraphNode ,
19
+ LGraphTriggerAction ,
20
+ LGraphTriggerParam
21
+ } from '../../lib/litegraph/src/litegraph'
22
+ import { NodeSlotType } from '../../lib/litegraph/src/types/globalEnums'
23
+
24
+ export interface WidgetSlotMetadata {
25
+ index : number
26
+ linked : boolean
27
+ }
17
28
18
29
export interface SafeWidgetData {
19
30
name : string
@@ -23,6 +34,7 @@ export interface SafeWidgetData {
23
34
options ?: Record < string , unknown >
24
35
callback ?: ( ( value : unknown ) => void ) | undefined
25
36
spec ?: InputSpec
37
+ slotMetadata ?: WidgetSlotMetadata
26
38
}
27
39
28
40
export interface VueNodeData {
@@ -66,14 +78,19 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
66
78
// Non-reactive storage for original LiteGraph nodes
67
79
const nodeRefs = new Map < string , LGraphNode > ( )
68
80
69
- const syncNodeSlotData = ( nodeId : string , node : LGraphNode ) => {
81
+ const refreshNodeSlots = ( nodeId : string ) => {
82
+ const nodeRef = nodeRefs . get ( nodeId )
70
83
const currentData = vueNodeData . get ( nodeId )
71
- if ( ! currentData ) return
84
+
85
+ if ( ! nodeRef || ! currentData ) return
86
+
87
+ const refreshedData = extractVueNodeData ( nodeRef )
72
88
73
89
vueNodeData . set ( nodeId , {
74
90
...currentData ,
75
- inputs : node . inputs ? [ ...node . inputs ] : undefined ,
76
- outputs : node . outputs ? [ ...node . outputs ] : undefined
91
+ widgets : refreshedData . widgets ,
92
+ inputs : refreshedData . inputs ,
93
+ outputs : refreshedData . outputs
77
94
} )
78
95
}
79
96
@@ -85,6 +102,16 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
85
102
? String ( node . graph . id )
86
103
: null
87
104
// Extract safe widget data
105
+ const slotMetadata = new Map < string , WidgetSlotMetadata > ( )
106
+
107
+ node . inputs ?. forEach ( ( input , index ) => {
108
+ if ( ! input ?. widget ?. name ) return
109
+ slotMetadata . set ( input . widget . name , {
110
+ index,
111
+ linked : input . link != null
112
+ } )
113
+ } )
114
+
88
115
const safeWidgets = node . widgets ?. map ( ( widget ) => {
89
116
try {
90
117
// TODO: Use widget.getReactiveData() once TypeScript types are updated
@@ -101,6 +128,7 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
101
128
value = widget . options . values [ 0 ]
102
129
}
103
130
const spec = nodeDefStore . getInputSpecForWidget ( node , widget . name )
131
+ const slotInfo = slotMetadata . get ( widget . name )
104
132
105
133
return {
106
134
name : widget . name ,
@@ -109,7 +137,8 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
109
137
label : widget . label ,
110
138
options : widget . options ? { ...widget . options } : undefined ,
111
139
callback : widget . callback ,
112
- spec
140
+ spec,
141
+ slotMetadata : slotInfo
113
142
}
114
143
} catch ( error ) {
115
144
return {
@@ -416,37 +445,27 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
416
445
handleNodeRemoved ( node , originalOnNodeRemoved )
417
446
}
418
447
419
- // Listen for property change events from instrumented nodes
420
- graph . onTrigger = ( action : string , param : unknown ) => {
421
- if (
422
- action === 'node:property:changed' &&
423
- param &&
424
- typeof param === 'object'
425
- ) {
426
- const event = param as {
427
- nodeId : string | number
428
- property : string
429
- oldValue : unknown
430
- newValue : unknown
431
- }
432
-
433
- const nodeId = String ( event . nodeId )
448
+ const triggerHandlers : {
449
+ [ K in LGraphTriggerAction ] : ( event : LGraphTriggerParam < K > ) => void
450
+ } = {
451
+ 'node:property:changed' : ( propertyEvent ) => {
452
+ const nodeId = String ( propertyEvent . nodeId )
434
453
const currentData = vueNodeData . get ( nodeId )
435
454
436
455
if ( currentData ) {
437
- switch ( event . property ) {
456
+ switch ( propertyEvent . property ) {
438
457
case 'title' :
439
458
vueNodeData . set ( nodeId , {
440
459
...currentData ,
441
- title : String ( event . newValue )
460
+ title : String ( propertyEvent . newValue )
442
461
} )
443
462
break
444
463
case 'flags.collapsed' :
445
464
vueNodeData . set ( nodeId , {
446
465
...currentData ,
447
466
flags : {
448
467
...currentData . flags ,
449
- collapsed : Boolean ( event . newValue )
468
+ collapsed : Boolean ( propertyEvent . newValue )
450
469
}
451
470
} )
452
471
break
@@ -455,53 +474,59 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
455
474
...currentData ,
456
475
flags : {
457
476
...currentData . flags ,
458
- pinned : Boolean ( event . newValue )
477
+ pinned : Boolean ( propertyEvent . newValue )
459
478
}
460
479
} )
461
480
break
462
481
case 'mode' :
463
482
vueNodeData . set ( nodeId , {
464
483
...currentData ,
465
- mode : typeof event . newValue === 'number' ? event . newValue : 0
484
+ mode :
485
+ typeof propertyEvent . newValue === 'number'
486
+ ? propertyEvent . newValue
487
+ : 0
466
488
} )
467
489
break
468
490
case 'color' :
469
491
vueNodeData . set ( nodeId , {
470
492
...currentData ,
471
493
color :
472
- typeof event . newValue === 'string'
473
- ? event . newValue
494
+ typeof propertyEvent . newValue === 'string'
495
+ ? propertyEvent . newValue
474
496
: undefined
475
497
} )
476
498
break
477
499
case 'bgcolor' :
478
500
vueNodeData . set ( nodeId , {
479
501
...currentData ,
480
502
bgcolor :
481
- typeof event . newValue === 'string'
482
- ? event . newValue
503
+ typeof propertyEvent . newValue === 'string'
504
+ ? propertyEvent . newValue
483
505
: undefined
484
506
} )
485
507
}
486
508
}
487
- } else if (
488
- ( action === 'node:slot-links:changed' ||
489
- action === 'node:slot-errors:changed' ) &&
490
- param &&
491
- typeof param === 'object'
492
- ) {
493
- const event = param as { nodeId : string | number }
494
- const nodeId = String ( event . nodeId )
495
- const node = nodeRefs . get ( nodeId )
496
- if ( node ) {
497
- syncNodeSlotData ( nodeId , node )
509
+ } ,
510
+ 'node:slot-errors:changed' : ( slotErrorsEvent ) => {
511
+ refreshNodeSlots ( String ( slotErrorsEvent . nodeId ) )
512
+ } ,
513
+ 'node:slot-links:changed' : ( slotLinksEvent ) => {
514
+ if ( slotLinksEvent . slotType === NodeSlotType . INPUT ) {
515
+ refreshNodeSlots ( String ( slotLinksEvent . nodeId ) )
498
516
}
499
517
}
518
+ }
500
519
501
- // Call original trigger handler if it exists
502
- if ( originalOnTrigger ) {
503
- originalOnTrigger ( action , param )
520
+ const isTriggerAction = ( value : string ) : value is LGraphTriggerAction =>
521
+ Object . prototype . hasOwnProperty . call ( triggerHandlers , value )
522
+
523
+ graph . onTrigger = ( action : string , event : unknown ) => {
524
+ if ( isTriggerAction ( action ) ) {
525
+ const handler = triggerHandlers [ action ] as ( payload : unknown ) => void
526
+ handler ( event )
504
527
}
528
+
529
+ originalOnTrigger ?.( action , event )
505
530
}
506
531
507
532
// Initialize state
0 commit comments