mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
## Summary Assorted cleanup opportunities found while working through the Vue node rendering logic cleanup. ## Review Focus Am I wrong that the readonly logic was never actually executing because it was defined as False in GraphCanvas when making each LGraphNode? Is there an edge case or some other reason that the ResizeObserver wouldn't work as a single signal to resize the canvas? ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5869-Cleanup-YAGNI-readonly-props-private-swap-on-ComfyApp-Canvas-resize-events-simplificat-27e6d73d3650811ba1dcf29e8d43091e) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
125 lines
3.4 KiB
Vue
125 lines
3.4 KiB
Vue
<template>
|
||
<div v-if="renderError" class="node-error p-1 text-red-500 text-xs">⚠️</div>
|
||
<div v-else v-tooltip.right="tooltipConfig" :class="slotWrapperClass">
|
||
<div class="relative">
|
||
<!-- Slot Name -->
|
||
<span
|
||
v-if="!dotOnly"
|
||
class="whitespace-nowrap text-sm font-normal dark-theme:text-slate-200 text-stone-200 lod-toggle"
|
||
>
|
||
{{ slotData.localized_name || slotData.name || `Output ${index}` }}
|
||
</span>
|
||
<LODFallback />
|
||
</div>
|
||
<!-- Connection Dot -->
|
||
<SlotConnectionDot
|
||
ref="connectionDotRef"
|
||
:color="slotColor"
|
||
class="translate-x-1/2"
|
||
@pointerdown="onPointerDown"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import {
|
||
type ComponentPublicInstance,
|
||
type Ref,
|
||
computed,
|
||
inject,
|
||
onErrorCaptured,
|
||
ref,
|
||
watchEffect
|
||
} from 'vue'
|
||
|
||
import { useErrorHandling } from '@/composables/useErrorHandling'
|
||
import { getSlotColor } from '@/constants/slotColors'
|
||
import type { INodeSlot } from '@/lib/litegraph/src/litegraph'
|
||
import { useNodeTooltips } from '@/renderer/extensions/vueNodes/composables/useNodeTooltips'
|
||
import { useSlotElementTracking } from '@/renderer/extensions/vueNodes/composables/useSlotElementTracking'
|
||
import { useSlotLinkInteraction } from '@/renderer/extensions/vueNodes/composables/useSlotLinkInteraction'
|
||
import { cn } from '@/utils/tailwindUtil'
|
||
|
||
import LODFallback from './LODFallback.vue'
|
||
import SlotConnectionDot from './SlotConnectionDot.vue'
|
||
|
||
interface OutputSlotProps {
|
||
nodeType?: string
|
||
nodeId?: string
|
||
slotData: INodeSlot
|
||
index: number
|
||
connected?: boolean
|
||
compatible?: boolean
|
||
dotOnly?: boolean
|
||
}
|
||
|
||
const props = defineProps<OutputSlotProps>()
|
||
|
||
// Error boundary implementation
|
||
const renderError = ref<string | null>(null)
|
||
|
||
const { toastErrorHandler } = useErrorHandling()
|
||
|
||
const tooltipContainer =
|
||
inject<Ref<HTMLElement | undefined>>('tooltipContainer')
|
||
const { getOutputSlotTooltip, createTooltipConfig } = useNodeTooltips(
|
||
props.nodeType || '',
|
||
tooltipContainer
|
||
)
|
||
|
||
const tooltipConfig = computed(() => {
|
||
const slotName = props.slotData.name || ''
|
||
const tooltipText = getOutputSlotTooltip(props.index)
|
||
const fallbackText = tooltipText || `Output: ${slotName}`
|
||
return createTooltipConfig(fallbackText)
|
||
})
|
||
|
||
onErrorCaptured((error) => {
|
||
renderError.value = error.message
|
||
toastErrorHandler(error)
|
||
return false
|
||
})
|
||
|
||
// Get slot color based on type
|
||
const slotColor = computed(() => getSlotColor(props.slotData.type))
|
||
|
||
const slotWrapperClass = computed(() =>
|
||
cn(
|
||
'lg-slot lg-slot--output flex items-center justify-end group rounded-l-lg h-6',
|
||
'cursor-crosshair',
|
||
props.dotOnly
|
||
? 'lg-slot--dot-only justify-center'
|
||
: 'pl-6 hover:bg-black/5 hover:dark:bg-white/5',
|
||
{
|
||
'lg-slot--connected': props.connected,
|
||
'lg-slot--compatible': props.compatible
|
||
}
|
||
)
|
||
)
|
||
|
||
const connectionDotRef = ref<ComponentPublicInstance<{
|
||
slotElRef: HTMLElement | undefined
|
||
}> | null>(null)
|
||
const slotElRef = ref<HTMLElement | null>(null)
|
||
|
||
// Watch for when the child component's ref becomes available
|
||
// Vue automatically unwraps the Ref when exposing it
|
||
watchEffect(() => {
|
||
const el = connectionDotRef.value?.slotElRef
|
||
slotElRef.value = el || null
|
||
})
|
||
|
||
useSlotElementTracking({
|
||
nodeId: props.nodeId ?? '',
|
||
index: props.index,
|
||
type: 'output',
|
||
element: slotElRef
|
||
})
|
||
|
||
const { onPointerDown } = useSlotLinkInteraction({
|
||
nodeId: props.nodeId ?? '',
|
||
index: props.index,
|
||
type: 'output'
|
||
})
|
||
</script>
|