mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-14 17:37:46 +00:00
feat: add WidgetValueStore for centralized widget value management (#8594)
## Summary Implements Phase 1 of the **Vue-owns-truth** pattern for widget values. Widget values are now canonical in a Pinia store; `widget.value` delegates to the store while preserving full backward compatibility. ## Changes - **New store**: `src/stores/widgetValueStore.ts` - centralized widget value storage with `get/set/remove/removeNode` API - **BaseWidget integration**: `widget.value` getter/setter now delegates to store when widget is associated with a node - **LGraphNode wiring**: `addCustomWidget()` automatically calls `widget.setNodeId(this.id)` to wire widgets to their nodes - **Test fixes**: Added Pinia setup to test files that use widgets ## Why This foundation enables: - Vue components to reactively bind to widget values via `computed(() => store.get(...))` - Future Yjs/CRDT backing for real-time collaboration - Cleaner separation between Vue state and LiteGraph rendering ## Backward Compatibility | Extension Pattern | Status | |-------------------|--------| | `widget.value = x` | ✅ Works unchanged | | `node.widgets[i].value` | ✅ Works unchanged | | `widget.callback` | ✅ Still fires | | `node.onWidgetChanged` | ✅ Still fires | ## Testing - ✅ 4252 unit tests pass - ✅ Build succeeds ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8594-feat-add-WidgetValueStore-for-centralized-widget-value-management-2fc6d73d36508160886fcb9f3ebd941e) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
@@ -1412,7 +1412,7 @@ export class GroupNodeHandler {
|
||||
handlerGroupData.oldToNewWidgetMap[Number(n)]?.[w]
|
||||
const widget = this.widgets.find((wg) => wg.name === widgetName)
|
||||
if (widget) {
|
||||
widget.type = 'hidden'
|
||||
widget.hidden = true
|
||||
widget.computeSize = () => [0, -4]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ useExtensionService().registerExtension({
|
||||
|
||||
const showValueWidget = ComfyWidgets['MARKDOWN'](
|
||||
this,
|
||||
'preview',
|
||||
'preview_markdown',
|
||||
['MARKDOWN', {}],
|
||||
app
|
||||
).widget as DOMWidget<HTMLTextAreaElement, string>
|
||||
|
||||
const showValueWidgetPlain = ComfyWidgets['STRING'](
|
||||
this,
|
||||
'preview',
|
||||
'preview_text',
|
||||
['STRING', { multiline: true }],
|
||||
app
|
||||
).widget as DOMWidget<HTMLTextAreaElement, string>
|
||||
@@ -48,6 +48,7 @@ useExtensionService().registerExtension({
|
||||
showValueWidgetPlain.options.hidden = value
|
||||
}
|
||||
|
||||
showValueWidget.label = 'Preview'
|
||||
showValueWidget.hidden = true
|
||||
showValueWidget.options.hidden = true
|
||||
showValueWidget.options.read_only = true
|
||||
@@ -55,6 +56,7 @@ useExtensionService().registerExtension({
|
||||
showValueWidget.element.disabled = true
|
||||
showValueWidget.serialize = false
|
||||
|
||||
showValueWidgetPlain.label = 'Preview'
|
||||
showValueWidgetPlain.hidden = false
|
||||
showValueWidgetPlain.options.hidden = false
|
||||
showValueWidgetPlain.options.read_only = true
|
||||
@@ -71,7 +73,7 @@ useExtensionService().registerExtension({
|
||||
: onExecuted.apply(this, [message])
|
||||
|
||||
const previewWidgets =
|
||||
this.widgets?.filter((w) => w.name === 'preview') ?? []
|
||||
this.widgets?.filter((w) => w.name.startsWith('preview_')) ?? []
|
||||
|
||||
for (const previewWidget of previewWidgets) {
|
||||
const text = message.text ?? ''
|
||||
|
||||
@@ -23,6 +23,7 @@ import { getNodeByLocatorId } from '@/utils/graphTraversalUtil'
|
||||
|
||||
import { api } from '../../scripts/api'
|
||||
import { app } from '../../scripts/app'
|
||||
import { useWidgetValueStore } from '@/stores/widgetValueStore'
|
||||
|
||||
function updateUIWidget(
|
||||
audioUIWidget: DOMWidget<HTMLAudioElement, string>,
|
||||
@@ -137,9 +138,16 @@ app.registerExtension({
|
||||
}
|
||||
}
|
||||
|
||||
let value = ''
|
||||
audioUIWidget.options.getValue = () => value
|
||||
audioUIWidget.options.setValue = (v) => (value = v)
|
||||
audioUIWidget.options.getValue = () =>
|
||||
(useWidgetValueStore().getWidget(node.id, inputName)
|
||||
?.value as string) ?? ''
|
||||
audioUIWidget.options.setValue = (v) => {
|
||||
const widgetState = useWidgetValueStore().getWidget(
|
||||
node.id,
|
||||
inputName
|
||||
)
|
||||
if (widgetState) widgetState.value = v
|
||||
}
|
||||
|
||||
return { widget: audioUIWidget }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user