fix: sync DOM widget values to widgetValueStore on registration (#9166)

## Summary

Override `setNodeId` in `BaseDOMWidgetImpl` to sync the DOM-resolved
value into the widget value store, fixing empty system prompts in Vue
nodes (Nodes 2.0).

## Changes

- **What**: DOM widgets (e.g. textarea for Gemini system_prompt) resolve
their value through `options.getValue()` / DOM elements, not
`_state.value`. When `BaseWidget.setNodeId` registers with the store, it
spreads `_state.value` which is `undefined` for DOM widgets. The
override captures the DOM-resolved value before registration and syncs
it into the store afterward — keeping the fix in the DOM widget layer
where the mismatch originates, leaving `BaseWidget` unchanged.

## Review Focus

- Whether capturing `this.value` before `super.setNodeId()` and writing
it after is the right sequencing
- Whether this correctly handles all DOM widget subtypes
(`DOMWidgetImpl`, `ComponentWidgetImpl`)

Supersedes #9164

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9166-fix-sync-DOM-widget-values-to-widgetValueStore-on-registration-3116d73d3650816f8cece866a9272baa)
by [Unito](https://www.unito.io)
This commit is contained in:
Hunter
2026-02-24 04:05:44 -05:00
committed by GitHub
parent a94574d379
commit 0f455c73bb
2 changed files with 62 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
import { createTestingPinia } from '@pinia/testing'
import { setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it } from 'vitest'
import { LGraph, LGraphNode } from '@/lib/litegraph/src/litegraph'
import { DOMWidgetImpl } from '@/scripts/domWidget'
import { useWidgetValueStore } from '@/stores/widgetValueStore'
describe('DOMWidgetImpl store integration', () => {
let graph: LGraph
let node: LGraphNode
let store: ReturnType<typeof useWidgetValueStore>
beforeEach(() => {
setActivePinia(createTestingPinia({ stubActions: false }))
store = useWidgetValueStore()
graph = new LGraph()
node = new LGraphNode('TestNode')
node.id = 1
graph.add(node)
})
it('registers DOM-resolved value in store via setNodeId', () => {
const defaultValue = 'You are an expert image-generation engine.'
const element = document.createElement('textarea')
element.value = defaultValue
const widget = new DOMWidgetImpl({
node,
name: 'system_prompt',
type: 'customtext',
element,
options: {
getValue: () => element.value as string,
setValue: (v: string) => {
element.value = v
const state = store.getWidget(graph.id, node.id, 'system_prompt')
if (state) state.value = v
}
}
})
widget.setNodeId(node.id)
const state = store.getWidget(graph.id, node.id, 'system_prompt')
expect(state?.value).toBe(defaultValue)
})
})