]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
chore: Merge branch 'edison/feat/fowardedSlots' into edison/testVapor
authordaiwei <daiwei521@126.com>
Thu, 12 Jun 2025 08:18:19 +0000 (16:18 +0800)
committerdaiwei <daiwei521@126.com>
Thu, 12 Jun 2025 08:18:19 +0000 (16:18 +0800)
1  2 
packages/runtime-vapor/src/block.ts
packages/runtime-vapor/src/componentSlots.ts
packages/runtime-vapor/src/vdomInterop.ts

index 31b71848dc2de6ac61a5571af2a2d4502e955ccb,b2d0ca04b67da88cc8c95ef05faae3686a5e0735..f0dbe7ab6c571a115ae4522269366a90ed865737
@@@ -38,10 -31,9 +39,9 @@@ export class VaporFragment 
  }
  
  export class DynamicFragment extends VaporFragment {
 -  anchor: Node
 +  anchor!: Node
    scope: EffectScope | undefined
    current?: BlockFn
-   fallback?: BlockFn
  
    constructor(anchorLabel?: string) {
      super([])
index 1ec6969bc98d05cbda5df296c5184b47710cb673,b8af4c91629be9e139137c688487e1ba563515ed..b250ecef4915088e3854260acc8cf4085ef8dbf9
@@@ -131,7 -123,8 +132,7 @@@ export function createSlot
      : EMPTY_OBJ
  
    let fragment: DynamicFragment
-   if (isRef(rawSlots._) && rawSlots._.value) {
 -
+   if (isRef(rawSlots._)) {
      fragment = instance.appContext.vapor!.vdomSlot(
        rawSlots._,
        name,
index ee8799039ba21516435a7645d5376b53a381ca08,a6b115f747494d519b080dd9548817987e23a1e8..cf67e3e518135bc82b36569133fbc3c56b52e45a
@@@ -2,21 -2,22 +2,25 @@@ import 
    type App,
    type ComponentInternalInstance,
    type ConcreteComponent,
 +  type HydrationRenderer,
    MoveType,
    type Plugin,
+   type RendererElement,
    type RendererInternals,
+   type RendererNode,
    type ShallowRef,
    type Slots,
    type VNode,
    type VaporInteropInterface,
    createVNode,
    currentInstance,
 +  ensureHydrationRenderer,
    ensureRenderer,
+   ensureVaporSlotFallback,
+   isVNode,
    onScopeDispose,
    renderSlot,
 +  shallowReactive,
    shallowRef,
    simpleSetCurrentInstance,
  } from '@vue/runtime-dom'
@@@ -273,77 -252,54 +293,71 @@@ function renderVDOMSlot
    frag.insert = (parentNode, anchor) => {
      if (!isMounted) {
        renderEffect(() => {
-         const vnode = renderSlot(
-           slotsRef.value,
-           isFunction(name) ? name() : name,
-           props,
-         )
-         if (isHydrating) {
-           locateHydrationNode(true)
-           ;(
-             vdomHydrateNode ||
-             (vdomHydrateNode = ensureHydrationRenderer().hydrateNode!)
-           )(
-             currentHydrationNode!,
-             vnode,
+         let vnode: VNode | undefined
+         let isValidSlot = false
+         // only render slot if rawSlots is defined and slot nodes are not empty
+         // otherwise, render fallback
+         if (slotsRef.value) {
+           vnode = renderSlot(
+             slotsRef.value,
+             isFunction(name) ? name() : name,
+             props,
+           )
+           let children = vnode.children as any[]
+           // handle forwarded vapor slot without its own fallback
+           // use the fallback provided by the slot outlet
+           ensureVaporSlotFallback(children, fallback as any)
+           isValidSlot = children.length > 0
+         }
+         if (isValidSlot) {
 -          if (fallbackNodes) {
++          if (isHydrating) {
++            locateHydrationNode(true)
++            ;(
++              vdomHydrateNode ||
++              (vdomHydrateNode = ensureHydrationRenderer().hydrateNode!)
++            )(
++              currentHydrationNode!,
++              vnode!,
++              parentComponent as any,
++              null,
++              null,
++              false,
++            )
++          } else if (fallbackNodes) {
+             remove(fallbackNodes, parentNode)
+             fallbackNodes = undefined
+           }
+           internals.p(
+             oldVNode,
+             vnode!,
+             parentNode,
+             anchor,
              parentComponent as any,
 +            null,
++            undefined,
 +            null,
 +            false,
            )
+           oldVNode = vnode!
          } else {
-           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
+           // for forwarded slot without its own fallback, use the fallback
+           // provided by the slot outlet.
+           // re-fetch `frag.fallback` as it may have been updated at `createSlot`
+           fallback = frag.fallback
+           if (fallback && !fallbackNodes) {
+             // mount fallback
+             if (oldVNode) {
+               internals.um(oldVNode, parentComponent as any, null, true)
              }
-             internals.p(
-               oldVNode,
-               vnode,
+             insert(
+               (fallbackNodes = fallback(internals, parentComponent)),
                parentNode,
                anchor,
-               parentComponent as any,
              )
-             oldVNode = vnode
-           } else {
-             if (fallback && !fallbackNodes) {
-               // mount fallback
-               if (oldVNode) {
-                 internals.um(oldVNode, parentComponent as any, null, true)
-               }
-               insert((fallbackNodes = fallback(props)), parentNode, anchor)
-             }
-             oldVNode = null
            }
+           oldVNode = null
          }
        })
        isMounted = true