mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-03 04:31:58 +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:
@@ -10,7 +10,11 @@ import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMuta
|
||||
import { LayoutSource } from '@/renderer/core/layout/types'
|
||||
import { adjustColor } from '@/utils/colorUtil'
|
||||
import type { ColorAdjustOptions } from '@/utils/colorUtil'
|
||||
import { commonType, toClass } from '@/lib/litegraph/src/utils/type'
|
||||
import {
|
||||
commonType,
|
||||
isNodeBindable,
|
||||
toClass
|
||||
} from '@/lib/litegraph/src/utils/type'
|
||||
|
||||
import { SUBGRAPH_OUTPUT_ID } from '@/lib/litegraph/src/constants'
|
||||
import type { DragAndScale } from './DragAndScale'
|
||||
@@ -1957,6 +1961,14 @@ export class LGraphNode
|
||||
this.widgets ||= []
|
||||
const widget = toConcreteWidget(custom_widget, this, false) ?? custom_widget
|
||||
this.widgets.push(widget)
|
||||
|
||||
// Only register with store if node has a valid ID (is already in a graph).
|
||||
// If the node isn't in a graph yet (id === -1), registration happens
|
||||
// when the node is added via LGraph.add() -> node.onAdded.
|
||||
if (this.id !== -1 && isNodeBindable(widget)) {
|
||||
widget.setNodeId(this.id)
|
||||
}
|
||||
|
||||
return widget
|
||||
}
|
||||
|
||||
@@ -3499,7 +3511,7 @@ export class LGraphNode
|
||||
* Toggles advanced mode of the node, showing advanced widgets
|
||||
*/
|
||||
toggleAdvanced() {
|
||||
if (!this.widgets?.some((w) => w.advanced)) return
|
||||
if (!this.hasAdvancedWidgets()) return
|
||||
if (!this.graph) throw new NullGraphError()
|
||||
this.graph._version++
|
||||
this.showAdvanced = !this.showAdvanced
|
||||
@@ -3877,6 +3889,21 @@ export class LGraphNode
|
||||
return !isHidden
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all widgets that should participate in layout calculations.
|
||||
* Filters out hidden widgets only (not collapsed/advanced).
|
||||
*/
|
||||
getLayoutWidgets(): IBaseWidget[] {
|
||||
return this.widgets?.filter((w) => !w.hidden) ?? []
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the node has any advanced widgets.
|
||||
*/
|
||||
hasAdvancedWidgets(): boolean {
|
||||
return this.widgets?.some((w) => w.advanced) ?? false
|
||||
}
|
||||
|
||||
updateComputedDisabled() {
|
||||
if (!this.widgets) return
|
||||
for (const widget of this.widgets)
|
||||
@@ -4087,7 +4114,7 @@ export class LGraphNode
|
||||
w: IBaseWidget
|
||||
}[] = []
|
||||
|
||||
const visibleWidgets = this.widgets.filter((w) => !w.hidden)
|
||||
const visibleWidgets = this.getLayoutWidgets()
|
||||
|
||||
for (const w of visibleWidgets) {
|
||||
if (w.computeSize) {
|
||||
|
||||
Reference in New Issue
Block a user