60 lines
1.7 KiB
TypeScript
60 lines
1.7 KiB
TypeScript
|
import { ComponentInstance } from './component'
|
||
|
import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode'
|
||
|
import { isArray, isObject, isFunction } from '@vue/shared'
|
||
|
|
||
|
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 = (rawSlot: Function): Slot => (props: any) =>
|
||
|
normalizeSlotValue(rawSlot(props))
|
||
|
|
||
|
export function resolveSlots(
|
||
|
instance: ComponentInstance,
|
||
|
children: NormalizedChildren
|
||
|
) {
|
||
|
let slots: Slots | void
|
||
|
if (isObject(children) && !isArray(children)) {
|
||
|
// pre-normalized slots object generated by compiler
|
||
|
if ((children as any)._normalized) {
|
||
|
slots = children as Slots
|
||
|
} else {
|
||
|
slots = {}
|
||
|
for (const key in children) {
|
||
|
let value = children[key]
|
||
|
if (isFunction(value)) {
|
||
|
;(slots as any)[key] = normalizeSlot(value)
|
||
|
} else {
|
||
|
if (__DEV__) {
|
||
|
// TODO show tip on using functions
|
||
|
console.log('use function slots!')
|
||
|
}
|
||
|
value = normalizeSlotValue(value)
|
||
|
;(slots as any)[key] = () => value
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else if (children != null) {
|
||
|
// Array, string or null.
|
||
|
// non object children passed to a component
|
||
|
if (__DEV__) {
|
||
|
// TODO show tip on using functions
|
||
|
console.log('use function slots!')
|
||
|
}
|
||
|
const normalized = normalizeSlotValue(children)
|
||
|
slots = { default: () => normalized }
|
||
|
}
|
||
|
if (slots !== void 0) {
|
||
|
instance.slots = slots
|
||
|
}
|
||
|
}
|