]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
chore: Merge branch 'minor' into edison/fix/vaporSlotFallback
authordaiwei <daiwei521@126.com>
Fri, 22 Aug 2025 07:54:16 +0000 (15:54 +0800)
committerdaiwei <daiwei521@126.com>
Fri, 22 Aug 2025 07:54:16 +0000 (15:54 +0800)
1  2 
packages/runtime-vapor/__tests__/componentSlots.spec.ts
packages/runtime-vapor/src/apiCreateFor.ts
packages/runtime-vapor/src/block.ts
packages/runtime-vapor/src/vdomInterop.ts

index ea9a3f8c8d7150763db1ddaa1d5f75efc53a0552,ff7aa56d05529acd72b10b05d3c7878b1e5299a9..54e754e5483acbda9e5737b30f743e2b898d686a
@@@ -12,17 -10,13 +12,18 @@@ import 
    insert,
    prepend,
    renderEffect,
+   setInsertionState,
    template,
  } from '../src'
 -import { currentInstance, nextTick, ref } from '@vue/runtime-dom'
 +import {
 +  currentInstance,
 +  nextTick,
 +  ref,
 +  toDisplayString,
 +} from '@vue/runtime-dom'
  import { makeRender } from './_utils'
  import type { DynamicSlot } from '../src/componentSlots'
 -import { setElementText } from '../src/dom/prop'
 +import { setElementText, setText } from '../src/dom/prop'
  
  const define = makeRender<any>()
  
@@@ -510,218 -504,34 +511,248 @@@ describe('component: slots', () => 
        expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
      })
  
+     test('consecutive slots with insertion state', async () => {
+       const { component: Child } = define({
+         setup() {
+           const n2 = template('<div><div>baz</div></div>', true)() as any
+           setInsertionState(n2, 0)
+           createSlot('default', null)
+           setInsertionState(n2, 0)
+           createSlot('foo', null)
+           return n2
+         },
+       })
+       const { html } = define({
+         setup() {
+           return createComponent(Child, null, {
+             default: () => template('default')(),
+             foo: () => template('foo')(),
+           })
+         },
+       }).render()
+       expect(html()).toBe(
+         `<div>` +
+           `default<!--slot-->` +
+           `foo<!--slot-->` +
+           `<div>baz</div>` +
+           `</div>`,
+       )
+     })
++
 +    test('render fallback when slot content is not valid', async () => {
 +      const Child = {
 +        setup() {
 +          return createSlot('default', null, () =>
 +            document.createTextNode('fallback'),
 +          )
 +        },
 +      }
 +
 +      const { html } = define({
 +        setup() {
 +          return createComponent(Child, null, {
 +            default: () => {
 +              return template('<!--comment-->')()
 +            },
 +          })
 +        },
 +      }).render()
 +
 +      expect(html()).toBe('fallback<!--slot-->')
 +    })
 +
 +    test('render fallback when v-if condition is false', async () => {
 +      const Child = {
 +        setup() {
 +          return createSlot('default', null, () =>
 +            document.createTextNode('fallback'),
 +          )
 +        },
 +      }
 +
 +      const toggle = ref(false)
 +
 +      const { html } = define({
 +        setup() {
 +          return createComponent(Child, null, {
 +            default: () => {
 +              return createIf(
 +                () => toggle.value,
 +                () => {
 +                  return document.createTextNode('content')
 +                },
 +              )
 +            },
 +          })
 +        },
 +      }).render()
 +
 +      expect(html()).toBe('fallback<!--if--><!--slot-->')
 +
 +      toggle.value = true
 +      await nextTick()
 +      expect(html()).toBe('content<!--if--><!--slot-->')
 +
 +      toggle.value = false
 +      await nextTick()
 +      expect(html()).toBe('fallback<!--if--><!--slot-->')
 +    })
 +
 +    test('render fallback with nested v-if', async () => {
 +      const Child = {
 +        setup() {
 +          return createSlot('default', null, () =>
 +            document.createTextNode('fallback'),
 +          )
 +        },
 +      }
 +
 +      const outerShow = ref(false)
 +      const innerShow = ref(false)
 +
 +      const { html } = define({
 +        setup() {
 +          return createComponent(Child, null, {
 +            default: () => {
 +              return createIf(
 +                () => outerShow.value,
 +                () => {
 +                  return createIf(
 +                    () => innerShow.value,
 +                    () => {
 +                      return document.createTextNode('content')
 +                    },
 +                  )
 +                },
 +              )
 +            },
 +          })
 +        },
 +      }).render()
 +
 +      expect(html()).toBe('fallback<!--if--><!--slot-->')
 +
 +      outerShow.value = true
 +      await nextTick()
 +      expect(html()).toBe('fallback<!--if--><!--if--><!--slot-->')
 +
 +      innerShow.value = true
 +      await nextTick()
 +      expect(html()).toBe('content<!--if--><!--if--><!--slot-->')
 +
 +      innerShow.value = false
 +      await nextTick()
 +      expect(html()).toBe('fallback<!--if--><!--if--><!--slot-->')
 +
 +      outerShow.value = false
 +      await nextTick()
 +      expect(html()).toBe('fallback<!--if--><!--slot-->')
 +
 +      outerShow.value = true
 +      await nextTick()
 +      expect(html()).toBe('fallback<!--if--><!--if--><!--slot-->')
 +
 +      innerShow.value = true
 +      await nextTick()
 +      expect(html()).toBe('content<!--if--><!--if--><!--slot-->')
 +    })
 +
 +    test('render fallback with v-for', async () => {
 +      const Child = {
 +        setup() {
 +          return createSlot('default', null, () =>
 +            document.createTextNode('fallback'),
 +          )
 +        },
 +      }
 +
 +      const items = ref<number[]>([1])
 +      const { html } = define({
 +        setup() {
 +          return createComponent(Child, null, {
 +            default: () => {
 +              const n2 = createFor(
 +                () => items.value,
 +                for_item0 => {
 +                  const n4 = template('<span> </span>')() as any
 +                  const x4 = child(n4) as any
 +                  renderEffect(() =>
 +                    setText(x4, toDisplayString(for_item0.value)),
 +                  )
 +                  return n4
 +                },
 +              )
 +              return n2
 +            },
 +          })
 +        },
 +      }).render()
 +
 +      expect(html()).toBe('<span>1</span><!--for--><!--slot-->')
 +
 +      items.value.pop()
 +      await nextTick()
 +      expect(html()).toBe('fallback<!--for--><!--slot-->')
 +
 +      items.value.pop()
 +      await nextTick()
 +      expect(html()).toBe('fallback<!--for--><!--slot-->')
 +
 +      items.value.push(2)
 +      await nextTick()
 +      expect(html()).toBe('<span>2</span><!--for--><!--slot-->')
 +    })
 +
 +    test('render fallback with v-for (empty source)', async () => {
 +      const Child = {
 +        setup() {
 +          return createSlot('default', null, () =>
 +            document.createTextNode('fallback'),
 +          )
 +        },
 +      }
 +
 +      const items = ref<number[]>([])
 +      const { html } = define({
 +        setup() {
 +          return createComponent(Child, null, {
 +            default: () => {
 +              const n2 = createFor(
 +                () => items.value,
 +                for_item0 => {
 +                  const n4 = template('<span> </span>')() as any
 +                  const x4 = child(n4) as any
 +                  renderEffect(() =>
 +                    setText(x4, toDisplayString(for_item0.value)),
 +                  )
 +                  return n4
 +                },
 +              )
 +              return n2
 +            },
 +          })
 +        },
 +      }).render()
 +
 +      expect(html()).toBe('fallback<!--for--><!--slot-->')
 +
 +      items.value.push(1)
 +      await nextTick()
 +      expect(html()).toBe('<span>1</span><!--for--><!--slot-->')
 +
 +      items.value.pop()
 +      await nextTick()
 +      expect(html()).toBe('fallback<!--for--><!--slot-->')
 +
 +      items.value.pop()
 +      await nextTick()
 +      expect(html()).toBe('fallback<!--for--><!--slot-->')
 +
 +      items.value.push(2)
 +      await nextTick()
 +      expect(html()).toBe('<span>2</span><!--for--><!--slot-->')
 +    })
    })
  })
Simple merge
index 1573a306922aacd6813fc8cdfe8f7c7a84ec4f4a,adc54526175c09642e2bb5f0d759e6835a63778a..239e2805b9c76453450485a40336831fc513f80a
@@@ -158,7 -158,7 +158,7 @@@ function createVDOMComponent
    rawProps?: LooseRawProps | null,
    rawSlots?: LooseRawSlots | null,
  ): VaporFragment {
--  const frag = new VaporFragment([])
++  const frag = new VaporFragment([] as Block[])
    const vnode = createVNode(
      component,
      rawProps && new Proxy(rawProps, rawPropsProxyHandlers),
          parentInstance as any,
        )
      }
 -    frag.nodes = vnode.el as Block
++    frag.nodes = [vnode.el] as Block[]
    }
  
    frag.remove = unmount