Support tooltips on DynamicCombos (#9717)

Tooltips are normally resolved through the node definition. Since
DynamicCombo added widgets are nested in the spec definition, this
lookup fails to find them. This PR makes it so that when a widget is
dynamically added using `litegraphService:addNodeInput`, any 'tooltiptip
defined in the provided inputSpec is applied on the widget.

The tooltip system does not current support tooltips for dynamiclly
added inputs. That can be considered for a followup PR.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9717-Support-tooltips-on-DynamicCombos-31f6d73d365081dc93f9eadd98572b3c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
AustinMroz
2026-03-11 00:17:37 -07:00
committed by GitHub
parent b129d64c5d
commit faed80e99a
4 changed files with 19 additions and 4 deletions

View File

@@ -324,7 +324,8 @@ function safeWidgetMapper(
}
: (extractWidgetDisplayOptions(effectiveWidget) ?? options),
slotMetadata: slotInfo,
slotName: name !== widget.name ? widget.name : undefined
slotName: name !== widget.name ? widget.name : undefined,
tooltip: widget.tooltip
}
} catch (error) {
return {

View File

@@ -27,7 +27,7 @@ function addDynamicCombo(node: LGraphNode, inputs: DynamicInputs) {
`${namePrefix}.${depth}.${inputIndex}`,
Array.isArray(input)
? ['COMFY_DYNAMICCOMBO_V3', { options: getSpec(input, depth + 1) }]
: [input, {}]
: [input, { tooltip: `${groupIndex}` }]
])
return {
key: `${groupIndex}`,
@@ -106,6 +106,13 @@ describe('Dynamic Combos', () => {
expect(node.inputs[1].name).toBe('0.0.0.0')
expect(node.inputs[3].name).toBe('2.2.0.0')
})
test('Dynamically added widgets have tooltips', () => {
const node = testNode()
addDynamicCombo(node, [['INT'], ['STRING']])
expect.soft(node.widgets[1].tooltip).toBe('0')
node.widgets[0].value = '1'
expect.soft(node.widgets[1].tooltip).toBe('1')
})
})
describe('Autogrow', () => {
const inputsSpec = { required: { image: ['IMAGE', {}] } }

View File

@@ -216,14 +216,18 @@ export const useLitegraphService = () => {
*/
function addNodeInput(node: LGraphNode, inputSpec: InputSpec) {
addInputSocket(node, inputSpec)
addInputWidget(node, inputSpec)
addInputWidget(node, inputSpec, { dynamic: true })
}
/**
* @internal Add a widget to the node. For both primitive types and custom widgets
* (unless `socketless`), an input socket is also added.
*/
function addInputWidget(node: LGraphNode, inputSpec: InputSpec) {
function addInputWidget(
node: LGraphNode,
inputSpec: InputSpec,
{ dynamic }: { dynamic?: boolean } = {}
) {
const widgetInputSpec = { ...inputSpec }
if (inputSpec.widgetType) {
widgetInputSpec.type = inputSpec.widgetType
@@ -254,6 +258,7 @@ export const useLitegraphService = () => {
advanced: inputSpec.advanced,
hidden: inputSpec.hidden
})
if (dynamic) widget.tooltip = inputSpec.tooltip
}
if (!widget?.options?.socketless) {

View File

@@ -74,6 +74,8 @@ export interface SimplifiedWidget<
/** Optional input specification backing this widget */
spec?: InputSpecV2
tooltip?: string
controlWidget?: SafeControlWidget
}