fix: correct Vue ref auto-unwrapping in slot components (#5378)

Fixed the misuse of exposed template refs in InputSlot and OutputSlot components.
When Vue exposes a Ref via defineExpose, it auto-unwraps it on the parent
component instance. The previous code was incorrectly double-unwrapping by
calling .value on an already unwrapped HTMLElement.

Changes:
- Updated type to ComponentPublicInstance with unwrapped HTMLElement
- Replaced watch with watchEffect for better timing handling
- Removed incorrect .value access on auto-unwrapped ref

This ensures slot elements are properly registered with useDomSlotRegistration,
fixing slot position tracking and hit-testing in the layout system.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Benjamin Lu
2025-09-06 03:37:39 -07:00
committed by GitHub
parent 0df7a53ead
commit 8445605777
2 changed files with 34 additions and 24 deletions

View File

@@ -32,7 +32,14 @@
</template>
<script setup lang="ts">
import { type Ref, computed, inject, onErrorCaptured, ref, watch } from 'vue'
import {
type ComponentPublicInstance,
computed,
inject,
onErrorCaptured,
ref,
watchEffect
} from 'vue'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { getSlotColor } from '@/constants/slotColors'
@@ -83,19 +90,17 @@ const transformState = inject<TransformState | undefined>(
undefined
)
const connectionDotRef = ref<{ slotElRef: Ref<HTMLElement> }>()
const connectionDotRef = ref<ComponentPublicInstance<{
slotElRef: HTMLElement | undefined
}> | null>(null)
const slotElRef = ref<HTMLElement | null>(null)
// Watch for connection dot ref changes and sync the element ref
watch(
connectionDotRef,
(newValue) => {
if (newValue?.slotElRef) {
slotElRef.value = newValue.slotElRef.value
}
},
{ immediate: true }
)
// 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
})
useDomSlotRegistration({
nodeId: props.nodeId ?? '',

View File

@@ -33,7 +33,14 @@
</template>
<script setup lang="ts">
import { type Ref, computed, inject, onErrorCaptured, ref, watch } from 'vue'
import {
type ComponentPublicInstance,
computed,
inject,
onErrorCaptured,
ref,
watchEffect
} from 'vue'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { getSlotColor } from '@/constants/slotColors'
@@ -82,19 +89,17 @@ const transformState = inject<TransformState | undefined>(
undefined
)
const connectionDotRef = ref<{ slotElRef: Ref<HTMLElement> }>()
const connectionDotRef = ref<ComponentPublicInstance<{
slotElRef: HTMLElement | undefined
}> | null>(null)
const slotElRef = ref<HTMLElement | null>(null)
// Watch for connection dot ref changes and sync the element ref
watch(
connectionDotRef,
(newValue) => {
if (newValue?.slotElRef) {
slotElRef.value = newValue.slotElRef.value
}
},
{ immediate: true }
)
// 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
})
useDomSlotRegistration({
nodeId: props.nodeId ?? '',