Skip to content

Commit dde7076

Browse files
committed
feat(compiler-vapor): add support for forwarded slots
1 parent 1ef6e6e commit dde7076

File tree

7 files changed

+57
-4
lines changed

7 files changed

+57
-4
lines changed

packages/compiler-vapor/src/generate.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
genCall,
1919
} from './generators/utils'
2020
import { setTemplateRefIdent } from './generators/templateRef'
21+
import { createForwardedSlotIdent } from './generators/slotOutlet'
2122

2223
export type CodegenOptions = Omit<BaseCodegenOptions, 'optimizeImports'>
2324

@@ -129,6 +130,12 @@ export function generate(
129130
`const ${setTemplateRefIdent} = ${context.helper('createTemplateRefSetter')}()`,
130131
)
131132
}
133+
if (ir.hasForwardedSlot) {
134+
push(
135+
NEWLINE,
136+
`const ${createForwardedSlotIdent} = ${context.helper('forwardedSlotCreator')}()`,
137+
)
138+
}
132139
push(...genBlockContent(ir.block, context, true))
133140
push(INDENT_END, NEWLINE)
134141

packages/compiler-vapor/src/generators/slotOutlet.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import { genExpression } from './expression'
55
import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
66
import { genRawProps } from './component'
77

8+
export const createForwardedSlotIdent = `_createForwardedSlot`
9+
810
export function genSlotOutlet(
911
oper: SlotOutletIRNode,
1012
context: CodegenContext,
1113
): CodeFragment[] {
1214
const { helper } = context
13-
const { id, name, fallback } = oper
15+
const { id, name, fallback, forwarded } = oper
1416
const [frag, push] = buildCodeFragment()
1517

1618
const nameExpr = name.isStatic
@@ -26,7 +28,7 @@ export function genSlotOutlet(
2628
NEWLINE,
2729
`const n${id} = `,
2830
...genCall(
29-
helper('createSlot'),
31+
forwarded ? createForwardedSlotIdent : helper('createSlot'),
3032
nameExpr,
3133
genRawProps(oper.props, context) || 'null',
3234
fallbackArg,

packages/compiler-vapor/src/ir/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export interface RootIRNode {
6666
directive: Set<string>
6767
block: BlockIRNode
6868
hasTemplateRef: boolean
69+
hasForwardedSlot: boolean
6970
}
7071

7172
export interface IfIRNode extends BaseIRNode {
@@ -209,6 +210,7 @@ export interface SlotOutletIRNode extends BaseIRNode {
209210
name: SimpleExpressionNode
210211
props: IRProps[]
211212
fallback?: BlockIRNode
213+
forwarded?: boolean
212214
parent?: number
213215
anchor?: number
214216
}

packages/compiler-vapor/src/transform.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ export function transform(
230230
directive: new Set(),
231231
block: newBlock(node),
232232
hasTemplateRef: false,
233+
hasForwardedSlot: false,
233234
}
234235

235236
const context = new TransformContext(ir, node, options)

packages/compiler-vapor/src/transforms/transformSlotOutlet.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ErrorCodes,
66
NodeTypes,
77
type SimpleExpressionNode,
8+
type TemplateChildNode,
89
createCompilerError,
910
createSimpleExpression,
1011
isStaticArgOf,
@@ -99,13 +100,21 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
99100
}
100101

101102
return () => {
103+
let forwarded = false
104+
const slotNode = context.block.node
105+
if (slotNode.type === NodeTypes.ELEMENT) {
106+
forwarded = hasForwardedSlots(slotNode.children)
107+
}
108+
if (forwarded) context.ir.hasForwardedSlot = true
109+
102110
exitBlock && exitBlock()
103111
context.dynamic.operation = {
104112
type: IRNodeTypes.SLOT_OUTLET_NODE,
105113
id,
106114
name: slotName,
107115
props: irProps,
108116
fallback,
117+
forwarded,
109118
}
110119
}
111120
}
@@ -131,3 +140,21 @@ function createFallback(
131140
context.reference()
132141
return [fallback, exitBlock]
133142
}
143+
144+
// TODO
145+
function hasForwardedSlots(children: TemplateChildNode[]): boolean {
146+
for (let i = 0; i < children.length; i++) {
147+
const child = children[i]
148+
switch (child.type) {
149+
case NodeTypes.ELEMENT:
150+
if (
151+
child.tagType === ElementTypes.SLOT ||
152+
hasForwardedSlots(child.children)
153+
) {
154+
return true
155+
}
156+
break
157+
}
158+
}
159+
return false
160+
}

packages/runtime-vapor/src/componentSlots.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,32 @@ export function getSlot(
8787
}
8888
}
8989

90+
export function forwardedSlotCreator(): (
91+
name: string | (() => string),
92+
rawProps?: LooseRawProps | null,
93+
fallback?: VaporSlot,
94+
) => Block {
95+
const instance = currentInstance as VaporComponentInstance
96+
return (
97+
name: string | (() => string),
98+
rawProps?: LooseRawProps | null,
99+
fallback?: VaporSlot,
100+
) => createSlot(name, rawProps, fallback, instance)
101+
}
102+
90103
export function createSlot(
91104
name: string | (() => string),
92105
rawProps?: LooseRawProps | null,
93106
fallback?: VaporSlot,
107+
i?: VaporComponentInstance,
94108
): Block {
95109
const _insertionParent = insertionParent
96110
const _insertionAnchor = insertionAnchor
97111
if (isHydrating) {
98112
locateHydrationNode()
99113
}
100114

101-
const instance = currentInstance as VaporComponentInstance
115+
const instance = i || (currentInstance as VaporComponentInstance)
102116
const rawSlots = instance.rawSlots
103117
const slotProps = rawProps
104118
? new Proxy(rawProps, rawPropsProxyHandlers)

packages/runtime-vapor/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export { insert, prepend, remove, isFragment, VaporFragment } from './block'
99
export { setInsertionState } from './insertionState'
1010
export { createComponent, createComponentWithFallback } from './component'
1111
export { renderEffect } from './renderEffect'
12-
export { createSlot } from './componentSlots'
12+
export { createSlot, forwardedSlotCreator } from './componentSlots'
1313
export { template } from './dom/template'
1414
export { createTextNode, child, nthChild, next } from './dom/node'
1515
export {

0 commit comments

Comments
 (0)