@@ -3,41 +3,57 @@ import {
3
3
type ConcreteComponent ,
4
4
type Plugin ,
5
5
type RendererInternals ,
6
+ type ShallowRef ,
7
+ type Slots ,
8
+ type VNode ,
6
9
type VaporInteropInterface ,
7
10
createVNode ,
8
11
currentInstance ,
9
12
ensureRenderer ,
13
+ renderSlot ,
10
14
shallowRef ,
11
15
simpleSetCurrentInstance ,
12
16
} from '@vue/runtime-dom'
13
17
import {
14
18
type LooseRawProps ,
15
19
type LooseRawSlots ,
20
+ type VaporComponent ,
16
21
VaporComponentInstance ,
17
22
createComponent ,
18
23
mountComponent ,
19
24
unmountComponent ,
20
25
} 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'
23
28
import { type RawProps , rawPropsProxyHandlers } from './componentProps'
24
- import type { RawSlots } from './componentSlots'
29
+ import type { RawSlots , VaporSlot } from './componentSlots'
30
+ import { renderEffect } from './renderEffect'
25
31
26
32
const vaporInteropImpl : Omit <
27
33
VaporInteropInterface ,
28
- 'vdomMount' | 'vdomUnmount'
34
+ 'vdomMount' | 'vdomUnmount' | 'vdomSlot'
29
35
> = {
30
36
mount ( vnode , container , anchor , parentComponent ) {
31
37
const selfAnchor = ( vnode . anchor = document . createComment ( 'vapor' ) )
32
38
container . insertBefore ( selfAnchor , anchor )
33
39
const prev = currentInstance
34
40
simpleSetCurrentInstance ( parentComponent )
41
+
35
42
const propsRef = shallowRef ( vnode . props )
43
+ const slotsRef = shallowRef ( vnode . children )
44
+
36
45
// @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
+ ) )
40
55
instance . rawPropsRef = propsRef
56
+ instance . rawSlotsRef = slotsRef
41
57
mountComponent ( instance , container , selfAnchor )
42
58
simpleSetCurrentInstance ( prev )
43
59
return instance
@@ -46,8 +62,9 @@ const vaporInteropImpl: Omit<
46
62
update ( n1 , n2 , shouldUpdate ) {
47
63
n2 . component = n1 . component
48
64
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
51
68
}
52
69
} ,
53
70
@@ -109,8 +126,66 @@ function createVDOMComponent(
109
126
}
110
127
frag . remove = ( ) => {
111
128
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
+ }
114
189
}
115
190
116
191
return frag
@@ -121,5 +196,6 @@ export const vaporInteropPlugin: Plugin = app => {
121
196
app . _context . vapor = extend ( vaporInteropImpl , {
122
197
vdomMount : createVDOMComponent . bind ( null , internals ) ,
123
198
vdomUnmount : internals . umt ,
199
+ vdomSlot : renderVDOMSlot . bind ( null , internals ) ,
124
200
} )
125
201
}
0 commit comments