From: daiwei Date: Fri, 22 Aug 2025 07:54:16 +0000 (+0800) Subject: chore: Merge branch 'minor' into edison/fix/vaporSlotFallback X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4a5de8c582419a85cc68e69a9fc95f18a67d3a13;p=thirdparty%2Fvuejs%2Fcore.git chore: Merge branch 'minor' into edison/fix/vaporSlotFallback --- 4a5de8c582419a85cc68e69a9fc95f18a67d3a13 diff --cc packages/runtime-vapor/__tests__/componentSlots.spec.ts index ea9a3f8c8d,ff7aa56d05..54e754e548 --- a/packages/runtime-vapor/__tests__/componentSlots.spec.ts +++ b/packages/runtime-vapor/__tests__/componentSlots.spec.ts @@@ -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() @@@ -510,218 -504,34 +511,248 @@@ describe('component: slots', () => expect(host.innerHTML).toBe('

') }) + test('consecutive slots with insertion state', async () => { + const { component: Child } = define({ + setup() { + const n2 = template('
baz
', 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( + `
` + + `default` + + `foo` + + `
baz
` + + `
`, + ) + }) ++ + 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('')() + }, + }) + }, + }).render() + + expect(html()).toBe('fallback') + }) + + 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') + + toggle.value = true + await nextTick() + expect(html()).toBe('content') + + toggle.value = false + await nextTick() + expect(html()).toBe('fallback') + }) + + 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') + + outerShow.value = true + await nextTick() + expect(html()).toBe('fallback') + + innerShow.value = true + await nextTick() + expect(html()).toBe('content') + + innerShow.value = false + await nextTick() + expect(html()).toBe('fallback') + + outerShow.value = false + await nextTick() + expect(html()).toBe('fallback') + + outerShow.value = true + await nextTick() + expect(html()).toBe('fallback') + + innerShow.value = true + await nextTick() + expect(html()).toBe('content') + }) + + test('render fallback with v-for', async () => { + const Child = { + setup() { + return createSlot('default', null, () => + document.createTextNode('fallback'), + ) + }, + } + + const items = ref([1]) + const { html } = define({ + setup() { + return createComponent(Child, null, { + default: () => { + const n2 = createFor( + () => items.value, + for_item0 => { + const n4 = template(' ')() as any + const x4 = child(n4) as any + renderEffect(() => + setText(x4, toDisplayString(for_item0.value)), + ) + return n4 + }, + ) + return n2 + }, + }) + }, + }).render() + + expect(html()).toBe('1') + + items.value.pop() + await nextTick() + expect(html()).toBe('fallback') + + items.value.pop() + await nextTick() + expect(html()).toBe('fallback') + + items.value.push(2) + await nextTick() + expect(html()).toBe('2') + }) + + test('render fallback with v-for (empty source)', async () => { + const Child = { + setup() { + return createSlot('default', null, () => + document.createTextNode('fallback'), + ) + }, + } + + const items = ref([]) + const { html } = define({ + setup() { + return createComponent(Child, null, { + default: () => { + const n2 = createFor( + () => items.value, + for_item0 => { + const n4 = template(' ')() as any + const x4 = child(n4) as any + renderEffect(() => + setText(x4, toDisplayString(for_item0.value)), + ) + return n4 + }, + ) + return n2 + }, + }) + }, + }).render() + + expect(html()).toBe('fallback') + + items.value.push(1) + await nextTick() + expect(html()).toBe('1') + + items.value.pop() + await nextTick() + expect(html()).toBe('fallback') + + items.value.pop() + await nextTick() + expect(html()).toBe('fallback') + + items.value.push(2) + await nextTick() + expect(html()).toBe('2') + }) }) }) diff --cc packages/runtime-vapor/src/vdomInterop.ts index 1573a30692,adc5452617..239e2805b9 --- a/packages/runtime-vapor/src/vdomInterop.ts +++ b/packages/runtime-vapor/src/vdomInterop.ts @@@ -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), @@@ -216,6 -216,8 +216,8 @@@ parentInstance as any, ) } + - frag.nodes = vnode.el as Block ++ frag.nodes = [vnode.el] as Block[] } frag.remove = unmount