@@ -3,41 +3,57 @@ import {
33 type ConcreteComponent ,
44 type Plugin ,
55 type RendererInternals ,
6+ type ShallowRef ,
7+ type Slots ,
8+ type VNode ,
69 type VaporInteropInterface ,
710 createVNode ,
811 currentInstance ,
912 ensureRenderer ,
13+ renderSlot ,
1014 shallowRef ,
1115 simpleSetCurrentInstance ,
1216} from '@vue/runtime-dom'
1317import {
1418 type LooseRawProps ,
1519 type LooseRawSlots ,
20+ type VaporComponent ,
1621 VaporComponentInstance ,
1722 createComponent ,
1823 mountComponent ,
1924 unmountComponent ,
2025} from './component'
21- import { VaporFragment , insert } from './block'
22- import { extend , remove } from '@vue/shared'
26+ import { type Block , VaporFragment , insert , remove } from './block'
27+ import { extend , isFunction , remove as removeItem } from '@vue/shared'
2328import { type RawProps , rawPropsProxyHandlers } from './componentProps'
24- import type { RawSlots } from './componentSlots'
29+ import type { RawSlots , VaporSlot } from './componentSlots'
30+ import { renderEffect } from './renderEffect'
2531
2632const vaporInteropImpl : Omit <
2733 VaporInteropInterface ,
28- 'vdomMount' | 'vdomUnmount'
34+ 'vdomMount' | 'vdomUnmount' | 'vdomSlot'
2935> = {
3036 mount ( vnode , container , anchor , parentComponent ) {
3137 const selfAnchor = ( vnode . anchor = document . createComment ( 'vapor' ) )
3238 container . insertBefore ( selfAnchor , anchor )
3339 const prev = currentInstance
3440 simpleSetCurrentInstance ( parentComponent )
41+
3542 const propsRef = shallowRef ( vnode . props )
43+ const slotsRef = shallowRef ( vnode . children )
44+
3645 // @ts -expect-error
37- const instance = ( vnode . component = createComponent ( vnode . type , {
38- $ : [ ( ) => propsRef . value ] ,
39- } ) )
46+ const instance = ( vnode . component = createComponent (
47+ vnode . type as any as VaporComponent ,
48+ {
49+ $ : [ ( ) => propsRef . value ] ,
50+ } as RawProps ,
51+ {
52+ _ : slotsRef , // pass the slots ref
53+ } as any as RawSlots ,
54+ ) )
4055 instance . rawPropsRef = propsRef
56+ instance . rawSlotsRef = slotsRef
4157 mountComponent ( instance , container , selfAnchor )
4258 simpleSetCurrentInstance ( prev )
4359 return instance
@@ -46,8 +62,9 @@ const vaporInteropImpl: Omit<
4662 update ( n1 , n2 , shouldUpdate ) {
4763 n2 . component = n1 . component
4864 if ( shouldUpdate ) {
49- ; ( n2 . component as any as VaporComponentInstance ) . rawPropsRef ! . value =
50- n2 . props
65+ const instance = n2 . component as any as VaporComponentInstance
66+ instance . rawPropsRef ! . value = n2 . props
67+ instance . rawSlotsRef ! . value = n2 . children
5168 }
5269 } ,
5370
@@ -109,8 +126,66 @@ function createVDOMComponent(
109126 }
110127 frag . remove = ( ) => {
111128 internals . umt ( vnode . component ! , null , true )
112- remove ( parentInstance . vdomChildren ! , vnode . component )
113- isMounted = false
129+ removeItem ( parentInstance . vdomChildren ! , vnode . component )
130+ }
131+
132+ return frag
133+ }
134+
135+ function renderVDOMSlot (
136+ internals : RendererInternals ,
137+ slotsRef : ShallowRef < Slots > ,
138+ name : string | ( ( ) => string ) ,
139+ props : Record < string , any > ,
140+ parentComponent : VaporComponentInstance ,
141+ fallback ?: VaporSlot ,
142+ ) : VaporFragment {
143+ const frag = new VaporFragment ( [ ] )
144+
145+ let isMounted = false
146+ let fallbackNodes : Block | undefined
147+ let parentNode : ParentNode
148+ let oldVNode : VNode | null = null
149+
150+ frag . insert = ( parent , anchor ) => {
151+ parentNode = parent
152+ if ( ! isMounted ) {
153+ renderEffect ( ( ) => {
154+ const vnode = renderSlot (
155+ slotsRef . value ,
156+ isFunction ( name ) ? name ( ) : name ,
157+ props ,
158+ )
159+ if ( ( vnode . children as any [ ] ) . length ) {
160+ if ( fallbackNodes ) {
161+ remove ( fallbackNodes , parentNode )
162+ fallbackNodes = undefined
163+ }
164+ internals . p ( oldVNode , vnode , parent , anchor , parentComponent as any )
165+ oldVNode = vnode
166+ } else {
167+ if ( fallback && ! fallbackNodes ) {
168+ // mount fallback
169+ if ( oldVNode ) {
170+ internals . um ( oldVNode , parentComponent as any , null , true )
171+ }
172+ insert ( ( fallbackNodes = fallback ( props ) ) , parent , anchor )
173+ }
174+ oldVNode = null
175+ }
176+ } )
177+ isMounted = true
178+ } else {
179+ // TODO move
180+ }
181+
182+ frag . remove = ( ) => {
183+ if ( fallbackNodes ) {
184+ remove ( fallbackNodes , parentNode )
185+ } else if ( oldVNode ) {
186+ internals . um ( oldVNode , parentComponent as any , null )
187+ }
188+ }
114189 }
115190
116191 return frag
@@ -121,5 +196,6 @@ export const vaporInteropPlugin: Plugin = app => {
121196 app . _context . vapor = extend ( vaporInteropImpl , {
122197 vdomMount : createVDOMComponent . bind ( null , internals ) ,
123198 vdomUnmount : internals . umt ,
199+ vdomSlot : renderVDOMSlot . bind ( null , internals ) ,
124200 } )
125201}
0 commit comments