]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(vdomInterop): handle forwarded vapor slots during render VDOM slot
authordaiwei <daiwei521@126.com>
Fri, 30 May 2025 08:27:02 +0000 (16:27 +0800)
committerdaiwei <daiwei521@126.com>
Fri, 30 May 2025 08:27:02 +0000 (16:27 +0800)
packages/runtime-vapor/src/componentProps.ts
packages/runtime-vapor/src/vdomInterop.ts

index 6de001ffb926a5f6ccb006c9622913cdfbcc882b..9cf65c57143a4f72b3b466cd5732bde7cd5cead1 100644 (file)
@@ -214,7 +214,8 @@ export function hasAttrFromRawProps(rawProps: RawProps, key: string): boolean {
   if (dynamicSources) {
     let i = dynamicSources.length
     while (i--) {
-      if (hasOwn(resolveSource(dynamicSources[i]), key)) {
+      const source = resolveSource(dynamicSources[i])
+      if (source && hasOwn(source, key)) {
         return true
       }
     }
index 6db627f03b550f89c2d8aac1f4bfe343f79e9482..33f6d4ca8047e9300a1c73fe1352c3992cec0ecb 100644 (file)
@@ -29,7 +29,14 @@ import {
   mountComponent,
   unmountComponent,
 } from './component'
-import { type Block, VaporFragment, insert, remove } from './block'
+import {
+  type Block,
+  VaporFragment,
+  insert,
+  isFragment,
+  isValidBlock,
+  remove,
+} from './block'
 import { EMPTY_OBJ, extend, isFunction } from '@vue/shared'
 import { type RawProps, rawPropsProxyHandlers } from './componentProps'
 import type { RawSlots, VaporSlot } from './componentSlots'
@@ -279,7 +286,36 @@ function renderVDOMSlot(
             false,
           )
         } else {
-          if ((vnode.children as any[]).length) {
+          let isValidSlotContent
+          let children = vnode.children as any[]
+          /*
+           * Handle forwarded vapor slot inside VDOM slot
+           * Example: In a vapor component template:
+           * <VDOMComp>
+           *   <template #header>
+           *     <slot name="header" />  <!-- This vapor slot gets forwarded -->
+           *   </template>
+           * </VDOMComp>
+           */
+          let vaporSlot
+          if (children.length === 1 && (vaporSlot = children[0].vs)) {
+            const block = vaporSlot.slot(props)
+            isValidSlotContent =
+              isValidBlock(block) ||
+              /*
+               * If block is a vapor fragment with insert, it indicates a forwarded VDOM slot
+               * Example: In a VDOM component template:
+               * <VaporComp>
+               *   <template #header>
+               *     <slot name="header" />  <!-- This VDOM slot gets forwarded -->
+               *   </template>
+               * </VaporComp>
+               */
+              (isFragment(block) && block.insert)
+          } else {
+            isValidSlotContent = children.length > 0
+          }
+          if (isValidSlotContent) {
             if (fallbackNodes) {
               remove(fallbackNodes, parentNode)
               fallbackNodes = undefined