Support display of multitype slots (#7457)

Example with forcibly modified types for testing
<img width="736" height="425" alt="image"
src="https://github.com/user-attachments/assets/e885a7d0-5946-41be-b9b4-b9b195f50c92"
/>

Vue mode doesn't currently seem to display optional inputs, but the SVGs
here include support for being made hollow with `--shape: url(#hollow)`
<img width="765" height="360" alt="image"
src="https://github.com/user-attachments/assets/0ea57179-99a4-4001-aa18-856e172287c0"
/>


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7457-Support-display-of-multitype-slots-2c86d73d3650818594afd988e73827e3)
by [Unito](https://www.unito.io)
This commit is contained in:
AustinMroz
2025-12-15 18:25:58 -08:00
committed by GitHub
parent 5d745c952a
commit 108cfaaa4b
6 changed files with 136 additions and 37 deletions

View File

@@ -20,13 +20,13 @@
<!-- Connection Dot -->
<SlotConnectionDot
ref="connectionDotRef"
:color="slotColor"
:class="
cn(
'-translate-x-1/2 w-3',
hasSlotError && 'ring-2 ring-error ring-offset-0 rounded-full'
)
"
:slot-data
@click="onClick"
@dblclick="onDoubleClick"
@pointerdown="onPointerDown"
@@ -54,7 +54,6 @@ import { computed, onErrorCaptured, ref, watchEffect } from 'vue'
import type { ComponentPublicInstance } from 'vue'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { getSlotColor } from '@/constants/slotColors'
import type { INodeSlot } from '@/lib/litegraph/src/litegraph'
import { useSlotLinkDragUIState } from '@/renderer/core/canvas/links/slotLinkDragUIState'
import { getSlotKey } from '@/renderer/core/layout/slots/slotIdentifier'
@@ -111,13 +110,6 @@ onErrorCaptured((error) => {
return false
})
const slotColor = computed(() => {
if (hasSlotError.value) {
return 'var(--color-error)'
}
return getSlotColor(props.slotData.type)
})
const { state: dragState } = useSlotLinkDragUIState()
const slotKey = computed(() =>
getSlotKey(props.nodeId ?? '', props.index, true)

View File

@@ -10,8 +10,8 @@
<!-- Connection Dot -->
<SlotConnectionDot
ref="connectionDotRef"
:color="slotColor"
class="w-3 translate-x-1/2"
:slot-data
@pointerdown="onPointerDown"
/>
</div>
@@ -22,7 +22,6 @@ import { computed, onErrorCaptured, ref, watchEffect } from 'vue'
import type { ComponentPublicInstance } from 'vue'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { getSlotColor } from '@/constants/slotColors'
import type { INodeSlot } from '@/lib/litegraph/src/litegraph'
import { useSlotLinkDragUIState } from '@/renderer/core/canvas/links/slotLinkDragUIState'
import { getSlotKey } from '@/renderer/core/layout/slots/slotIdentifier'
@@ -67,9 +66,6 @@ onErrorCaptured((error) => {
return false
})
// Get slot color based on type
const slotColor = computed(() => getSlotColor(props.slotData.type))
const { state: dragState } = useSlotLinkDragUIState()
const slotKey = computed(() =>
getSlotKey(props.nodeId ?? '', props.index, false)

View File

@@ -1,20 +1,45 @@
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import { computed, useTemplateRef } from 'vue'
import { getSlotColor } from '@/constants/slotColors'
import type { INodeSlot } from '@/lib/litegraph/src/litegraph'
import { cn } from '@/utils/tailwindUtil'
import type { ClassValue } from '@/utils/tailwindUtil'
const props = defineProps<{
color?: string
multi?: boolean
slotData?: INodeSlot
class?: ClassValue
hasError?: boolean
multi?: boolean
}>()
const slotElRef = useTemplateRef('slot-el')
function getTypes() {
if (props.hasError) return ['var(--color-error)']
//TODO Support connected/disconnected colors?
if (!props.slotData) return [getSlotColor()]
const typesSet = new Set(
`${props.slotData.type}`.split(',').map(getSlotColor)
)
return [...typesSet].slice(0, 3)
}
const types = getTypes()
defineExpose({
slotElRef
})
const slotClass = computed(() =>
cn(
'bg-slate-300 rounded-full slot-dot',
'transition-all duration-150',
'border border-solid border-node-component-slot-dot-outline',
props.multi
? 'w-3 h-6'
: 'size-3 cursor-crosshair group-hover/slot:[--node-component-slot-dot-outline-opacity-mult:5] group-hover/slot:scale-125'
)
)
</script>
<template>
@@ -27,19 +52,26 @@ defineExpose({
"
>
<div
v-if="types.length === 1"
ref="slot-el"
class="slot-dot"
:style="{ backgroundColor: color }"
:class="
cn(
'bg-slate-300 rounded-full',
'transition-all duration-150',
'border border-solid border-node-component-slot-dot-outline',
!multi &&
'cursor-crosshair group-hover/slot:[--node-component-slot-dot-outline-opacity-mult:5] group-hover/slot:scale-125',
multi ? 'w-3 h-6' : 'size-3'
)
"
:style="{ backgroundColor: types[0] }"
:class="slotClass"
/>
<div
v-else
ref="slot-el"
:style="{
'--type1': types[0],
'--type2': types[1],
'--type3': types[2]
}"
:class="slotClass"
>
<i-comfy:node-slot2
v-if="types.length === 2"
class="size-full -translate-y-1/2"
/>
<i-comfy:node-slot3 v-else class="size-full -translate-y-1/2" />
</div>
</div>
</template>