75 lines
2.2 KiB
TypeScript
75 lines
2.2 KiB
TypeScript
import { ComponentInstance, currentInstance } from './component'
|
|
import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode'
|
|
import { isArray, isFunction } from '@vue/shared'
|
|
import { ShapeFlags } from './shapeFlags'
|
|
import { warn } from './warning'
|
|
|
|
export type Slot = (...args: any[]) => VNode[]
|
|
export type Slots = Readonly<{
|
|
[name: string]: Slot
|
|
}>
|
|
export type RawSlots = {
|
|
[name: string]: unknown
|
|
}
|
|
|
|
const normalizeSlotValue = (value: unknown): VNode[] =>
|
|
isArray(value)
|
|
? value.map(normalizeVNode)
|
|
: [normalizeVNode(value as VNodeChild)]
|
|
|
|
const normalizeSlot = (key: string, rawSlot: Function): Slot => (
|
|
props: any
|
|
) => {
|
|
if (__DEV__ && currentInstance != null) {
|
|
warn(
|
|
`Slot "${key}" invoked outside of the render function: ` +
|
|
`this will not track dependencies used in the slot. ` +
|
|
`Invoke the slot function inside the render function instead.`
|
|
)
|
|
}
|
|
return normalizeSlotValue(rawSlot(props))
|
|
}
|
|
|
|
export function resolveSlots(
|
|
instance: ComponentInstance,
|
|
children: NormalizedChildren
|
|
) {
|
|
let slots: Slots | void
|
|
if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
|
|
if ((children as any)._normalized) {
|
|
// pre-normalized slots object generated by compiler
|
|
slots = children as Slots
|
|
} else {
|
|
slots = {}
|
|
for (const key in children as RawSlots) {
|
|
let value = (children as RawSlots)[key]
|
|
if (isFunction(value)) {
|
|
;(slots as any)[key] = normalizeSlot(key, value)
|
|
} else {
|
|
if (__DEV__) {
|
|
warn(
|
|
`Non-function value encountered for slot "${key}". ` +
|
|
`Prefer function slots for better performance.`
|
|
)
|
|
}
|
|
value = normalizeSlotValue(value)
|
|
;(slots as any)[key] = () => value
|
|
}
|
|
}
|
|
}
|
|
} else if (children !== null) {
|
|
// non slot object children (direct value) passed to a component
|
|
if (__DEV__) {
|
|
warn(
|
|
`Non-function value encountered for default slot. ` +
|
|
`Prefer function slots for better performance.`
|
|
)
|
|
}
|
|
const normalized = normalizeSlotValue(children)
|
|
slots = { default: () => normalized }
|
|
}
|
|
if (slots !== void 0) {
|
|
instance.slots = slots
|
|
}
|
|
}
|