From 4dac3ccb22cd467c8a84afc18e23d71c5e109eb8 Mon Sep 17 00:00:00 2001 From: DrJKL Date: Tue, 30 Jun 2026 14:25:12 -0700 Subject: [PATCH] fix: restore Load3D widget rendering --- .../litegraph/src/widgets/BaseWidget.test.ts | 57 ++++++++++++++++++- src/lib/litegraph/src/widgets/BaseWidget.ts | 4 ++ .../composables/useProcessedWidgets.test.ts | 12 ++++ .../composables/useProcessedWidgets.ts | 3 + 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/lib/litegraph/src/widgets/BaseWidget.test.ts b/src/lib/litegraph/src/widgets/BaseWidget.test.ts index 2573babe16..f0679640a9 100644 --- a/src/lib/litegraph/src/widgets/BaseWidget.test.ts +++ b/src/lib/litegraph/src/widgets/BaseWidget.test.ts @@ -4,7 +4,15 @@ import { setActivePinia } from 'pinia' import { beforeEach, describe, expect, it } from 'vitest' import { LGraph, LGraphNode } from '@/lib/litegraph/src/litegraph' -import type { INumericWidget } from '@/lib/litegraph/src/types/widgets' +import type { + IBaseWidget, + INumericWidget +} from '@/lib/litegraph/src/types/widgets' +import { BaseWidget } from '@/lib/litegraph/src/widgets/BaseWidget' +import type { + DrawWidgetOptions, + WidgetEventOptions +} from '@/lib/litegraph/src/widgets/BaseWidget' import { NumberWidget } from '@/lib/litegraph/src/widgets/NumberWidget' import { useWidgetValueStore } from '@/stores/widgetValueStore' import { toNodeId } from '@/types/nodeId' @@ -27,6 +35,28 @@ function createTestWidget( ) } +class MutableTypeWidget extends BaseWidget> { + drawWidget( + _ctx: CanvasRenderingContext2D, + _options: DrawWidgetOptions + ): void {} + + onClick(_options: WidgetEventOptions): void {} +} + +function createMutableTypeWidget(node: LGraphNode): MutableTypeWidget { + return new MutableTypeWidget( + { + type: 'number', + name: 'typeChangedWidget', + value: 42, + options: { min: 0, max: 100 }, + y: 0 + }, + node + ) +} + describe('BaseWidget store integration', () => { let graph: LGraph let node: LGraphNode @@ -175,6 +205,31 @@ describe('BaseWidget store integration', () => { store.getWidget(widgetId(graph.id, toNodeId(1), 'valuesWidget'))?.value ).toBe(77) }) + + it('registers the live widget type', () => { + const widget = createMutableTypeWidget(node) + widget.type = 'number-custom' + + widget.setNodeId(toNodeId(1)) + + expect( + store.getWidget(widgetId(graph.id, toNodeId(1), 'typeChangedWidget')) + ?.type + ).toBe('number-custom') + }) + + it('stores explicit isDOMWidget false over component presence', () => { + const widget = createTestWidget(node, { name: 'flaggedDomWidget' }) + Object.assign(widget, { component: {}, isDOMWidget: false }) + + widget.setNodeId(toNodeId(1)) + + expect( + store.getWidgetRenderState( + widgetId(graph.id, toNodeId(1), 'flaggedDomWidget') + )?.isDOMWidget + ).toBe(false) + }) }) describe('DOM widget value registration', () => { diff --git a/src/lib/litegraph/src/widgets/BaseWidget.ts b/src/lib/litegraph/src/widgets/BaseWidget.ts index 90f54dfe64..d3eb5368dc 100644 --- a/src/lib/litegraph/src/widgets/BaseWidget.ts +++ b/src/lib/litegraph/src/widgets/BaseWidget.ts @@ -47,6 +47,9 @@ export interface WidgetEventOptions { } function isDOMBackedWidget(widget: IBaseWidget): boolean { + if ('isDOMWidget' in widget && typeof widget.isDOMWidget === 'boolean') { + return widget.isDOMWidget + } return ( ('element' in widget && !!widget.element) || ('component' in widget && !!widget.component) @@ -158,6 +161,7 @@ export abstract class BaseWidget const id = widgetId(graphId, nodeId, this.name) this._state = store.registerWidget(id, { ...this._state, + type: this.type, value: this.value }) store.registerWidgetRenderState(id, { diff --git a/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.test.ts b/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.test.ts index 5ec20aeaca..4cdf0f7a57 100644 --- a/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.test.ts +++ b/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.test.ts @@ -12,6 +12,8 @@ import { hasWidgetError, isWidgetVisible } from '@/renderer/extensions/vueNodes/composables/useProcessedWidgets' +import WidgetDOM from '@/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue' +import WidgetLegacy from '@/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue' import { useExecutionErrorStore } from '@/stores/executionErrorStore' import { useWidgetValueStore } from '@/stores/widgetValueStore' import { @@ -445,6 +447,16 @@ describe('computeProcessedWidgets', () => { } }) }) + + it('treats explicit isDOMWidget false as authoritative', () => { + const widget = createMockWidget({ name: 'custom', type: 'unknown' }) + Object.assign(widget, { component: {}, isDOMWidget: false }) + + const result = processWidgets({ widgets: [widget] }) + + expect(result[0].vueComponent).toBe(WidgetLegacy) + expect(result[0].vueComponent).not.toBe(WidgetDOM) + }) }) describe('createWidgetUpdateHandler (via computeProcessedWidgets)', () => { diff --git a/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.ts b/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.ts index 90516eaeeb..9f1f388f12 100644 --- a/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.ts +++ b/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.ts @@ -150,6 +150,9 @@ function normalizeWidgetValue(value: unknown): WidgetValue { } function isDOMBackedWidget(widget: IBaseWidget): boolean { + if ('isDOMWidget' in widget && typeof widget.isDOMWidget === 'boolean') { + return widget.isDOMWidget + } return ( ('element' in widget && !!widget.element) || ('component' in widget && !!widget.component)