refactor(LGraph): dispatch trigger events through events target

Adds the four node trigger event payloads (property/slot-errors/
slot-links/slot-label) to LGraphEventMap and makes LGraph.trigger()
dispatch via this.events in addition to calling onTrigger.

Removes the leaky onTrigger monkey-patch in AppModeWidgetList.vue,
replacing it with useEventListener on the events target. The
onTrigger callback path is preserved for back-compat with
useGraphNodeManager (see FE-667 for converting that one too).
This commit is contained in:
DrJKL
2026-05-12 01:45:56 -07:00
parent a46dee5eed
commit c2c1621fd2
3 changed files with 30 additions and 18 deletions

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { useEventListener } from '@vueuse/core'
import { computed, onBeforeUnmount, provide, shallowRef, triggerRef } from 'vue'
import { computed, provide, shallowRef, triggerRef } from 'vue'
import { useAppModeWidgetResizing } from '@/components/builder/useAppModeWidgetResizing'
import { useI18n } from 'vue-i18n'
@@ -63,17 +63,9 @@ useEventListener(
'configured',
() => (graphNodes.value = app.rootGraph.nodes)
)
// `LGraph.trigger()` invokes `onTrigger` synchronously but does not dispatch
// on `events`, so chain through `onTrigger` to react to slot-label renames.
const previousOnTrigger = app.rootGraph.onTrigger
app.rootGraph.onTrigger = (event) => {
previousOnTrigger?.(event)
if (event.type === 'node:slot-label:changed') triggerRef(graphNodes)
}
onBeforeUnmount(() => {
if (app.rootGraph.onTrigger === undefined) return
app.rootGraph.onTrigger = previousOnTrigger
})
useEventListener(app.rootGraph.events, 'node:slot-label:changed', () =>
triggerRef(graphNodes)
)
const mappedSelections = computed((): WidgetEntry[] => {
void graphNodes.value

View File

@@ -1364,18 +1364,17 @@ export class LGraph
): void
trigger(action: string, param: unknown): void
trigger(action: string, param: unknown) {
// Convert to discriminated union format for typed handlers
const validEventTypes = new Set([
const validEventTypes = new Set<LGraphTriggerAction>([
'node:slot-links:changed',
'node:slot-errors:changed',
'node:property:changed',
'node:slot-label:changed'
])
if (!validEventTypes.has(action as LGraphTriggerAction)) return
if (!param || typeof param !== 'object') return
if (validEventTypes.has(action) && param && typeof param === 'object') {
this.onTrigger?.({ type: action, ...param } as LGraphTriggerEvent)
}
// Don't handle unknown events - just ignore them
this.onTrigger?.({ type: action, ...param } as LGraphTriggerEvent)
this.events.dispatch(action as LGraphTriggerAction, param as never)
}
/** @todo Clean up - never implemented. */

View File

@@ -1,7 +1,9 @@
import type { LGraph } from '@/lib/litegraph/src/LGraph'
import type { NodeId } from '@/lib/litegraph/src/LGraphNode'
import type { LLink, ResolvedConnection } from '@/lib/litegraph/src/LLink'
import type { ReadOnlyRect } from '@/lib/litegraph/src/interfaces'
import type { Subgraph } from '@/lib/litegraph/src/subgraph/Subgraph'
import type { NodeSlotType } from '@/lib/litegraph/src/types/globalEnums'
import type {
ExportedSubgraph,
ISerialisedGraph,
@@ -48,4 +50,23 @@ export interface LGraphEventMap {
subgraph: Subgraph
closingGraph: LGraph | Subgraph
}
'node:property:changed': {
nodeId: NodeId
property: string
oldValue: unknown
newValue: unknown
}
'node:slot-errors:changed': { nodeId: NodeId }
'node:slot-links:changed': {
nodeId: NodeId
slotType: NodeSlotType
slotIndex: number
connected: boolean
linkId: number
}
'node:slot-label:changed': {
nodeId: NodeId
slotType?: NodeSlotType
}
}