2019-09-05 23:11:33 +08:00
|
|
|
import {
|
|
|
|
VNodeTypes,
|
|
|
|
VNode,
|
|
|
|
createVNode,
|
|
|
|
VNodeChildren,
|
|
|
|
Fragment,
|
|
|
|
Portal
|
|
|
|
} from './vnode'
|
2019-08-24 03:27:17 +08:00
|
|
|
import { isObject, isArray } from '@vue/shared'
|
2019-09-05 23:11:33 +08:00
|
|
|
import { Ref } from '@vue/reactivity'
|
|
|
|
import { RawSlots } from './componentSlots'
|
2019-09-06 23:19:22 +08:00
|
|
|
import { FunctionalComponent } from './component'
|
2019-09-05 23:11:33 +08:00
|
|
|
import {
|
|
|
|
ComponentOptionsWithoutProps,
|
|
|
|
ComponentOptionsWithArrayProps,
|
2019-10-08 21:26:09 +08:00
|
|
|
ComponentOptionsWithObjectProps,
|
2019-09-06 06:48:49 +08:00
|
|
|
ComponentOptions
|
2019-10-02 22:03:43 +08:00
|
|
|
} from './apiOptions'
|
2019-09-05 23:11:33 +08:00
|
|
|
import { ExtractPropTypes } from './componentProps'
|
2019-08-24 03:27:17 +08:00
|
|
|
|
|
|
|
// `h` is a more user-friendly version of `createVNode` that allows omitting the
|
|
|
|
// props when possible. It is intended for manually written render functions.
|
|
|
|
// Compiler-generated code uses `createVNode` because
|
|
|
|
// 1. it is monomorphic and avoids the extra call overhead
|
|
|
|
// 2. it allows specifying patchFlags for optimization
|
|
|
|
|
|
|
|
/*
|
|
|
|
// type only
|
|
|
|
h('div')
|
|
|
|
|
|
|
|
// type + props
|
|
|
|
h('div', {})
|
|
|
|
|
|
|
|
// type + omit props + children
|
|
|
|
// Omit props does NOT support named slots
|
|
|
|
h('div', []) // array
|
|
|
|
h('div', () => {}) // default slot
|
|
|
|
h('div', 'foo') // text
|
|
|
|
|
|
|
|
// type + props + children
|
|
|
|
h('div', {}, []) // array
|
|
|
|
h('div', {}, () => {}) // default slot
|
|
|
|
h('div', {}, {}) // named slots
|
|
|
|
h('div', {}, 'foo') // text
|
|
|
|
|
|
|
|
// named slots without props requires explicit `null` to avoid ambiguity
|
|
|
|
h('div', null, {})
|
|
|
|
**/
|
|
|
|
|
2019-09-07 00:58:31 +08:00
|
|
|
export interface RawProps {
|
2019-09-05 23:11:33 +08:00
|
|
|
[key: string]: any
|
|
|
|
key?: string | number
|
2019-10-10 02:01:53 +08:00
|
|
|
ref?: string | Ref | Function
|
2019-09-05 23:11:33 +08:00
|
|
|
// used to differ from a single VNode object as children
|
|
|
|
_isVNode?: never
|
|
|
|
// used to differ from Array children
|
|
|
|
[Symbol.iterator]?: never
|
|
|
|
}
|
|
|
|
|
2019-09-07 00:58:31 +08:00
|
|
|
export type RawChildren =
|
|
|
|
| string
|
|
|
|
| number
|
|
|
|
| boolean
|
|
|
|
| VNodeChildren
|
|
|
|
| (() => any)
|
|
|
|
|
|
|
|
export { RawSlots }
|
2019-09-05 23:11:33 +08:00
|
|
|
|
|
|
|
// fake constructor type returned from `createComponent`
|
|
|
|
interface Constructor<P = any> {
|
|
|
|
new (): { $props: P }
|
|
|
|
}
|
|
|
|
|
|
|
|
// The following is a series of overloads for providing props validation of
|
|
|
|
// manually written render functions.
|
|
|
|
|
|
|
|
// element
|
2019-09-07 00:58:31 +08:00
|
|
|
export function h(type: string, children?: RawChildren): VNode
|
2019-09-05 23:11:33 +08:00
|
|
|
export function h(
|
|
|
|
type: string,
|
2019-09-07 00:58:31 +08:00
|
|
|
props?: RawProps | null,
|
|
|
|
children?: RawChildren
|
2019-09-05 23:11:33 +08:00
|
|
|
): VNode
|
|
|
|
|
|
|
|
// keyed fragment
|
2019-09-07 00:58:31 +08:00
|
|
|
export function h(type: typeof Fragment, children?: RawChildren): VNode
|
2019-09-05 23:11:33 +08:00
|
|
|
export function h(
|
|
|
|
type: typeof Fragment,
|
2019-09-07 00:58:31 +08:00
|
|
|
props?: (RawProps & { key?: string | number }) | null,
|
|
|
|
children?: RawChildren
|
2019-09-05 23:11:33 +08:00
|
|
|
): VNode
|
|
|
|
|
|
|
|
// portal
|
2019-09-07 00:58:31 +08:00
|
|
|
export function h(type: typeof Portal, children?: RawChildren): VNode
|
2019-09-05 23:11:33 +08:00
|
|
|
export function h(
|
|
|
|
type: typeof Portal,
|
2019-09-07 00:58:31 +08:00
|
|
|
props?: (RawProps & { target: any }) | null,
|
|
|
|
children?: RawChildren
|
2019-09-05 23:11:33 +08:00
|
|
|
): VNode
|
|
|
|
|
|
|
|
// functional component
|
2019-09-07 00:58:31 +08:00
|
|
|
export function h(type: FunctionalComponent, children?: RawChildren): VNode
|
2019-09-05 23:11:33 +08:00
|
|
|
export function h<P>(
|
|
|
|
type: FunctionalComponent<P>,
|
2019-09-07 00:58:31 +08:00
|
|
|
props?: (RawProps & P) | null,
|
|
|
|
children?: RawChildren | RawSlots
|
2019-09-05 23:11:33 +08:00
|
|
|
): VNode
|
|
|
|
|
|
|
|
// stateful component
|
2019-09-07 00:58:31 +08:00
|
|
|
export function h(type: ComponentOptions, children?: RawChildren): VNode
|
2019-09-05 23:11:33 +08:00
|
|
|
export function h<P>(
|
|
|
|
type: ComponentOptionsWithoutProps<P>,
|
2019-09-07 00:58:31 +08:00
|
|
|
props?: (RawProps & P) | null,
|
|
|
|
children?: RawChildren | RawSlots
|
2019-09-05 23:11:33 +08:00
|
|
|
): VNode
|
|
|
|
export function h<P extends string>(
|
|
|
|
type: ComponentOptionsWithArrayProps<P>,
|
|
|
|
// TODO for now this doesn't really do anything, but it would become useful
|
|
|
|
// if we make props required by default
|
2019-09-07 00:58:31 +08:00
|
|
|
props?: (RawProps & { [key in P]?: any }) | null,
|
|
|
|
children?: RawChildren | RawSlots
|
2019-09-05 23:11:33 +08:00
|
|
|
): VNode
|
|
|
|
export function h<P>(
|
2019-10-08 21:26:09 +08:00
|
|
|
type: ComponentOptionsWithObjectProps<P>,
|
2019-09-07 00:58:31 +08:00
|
|
|
props?: (RawProps & ExtractPropTypes<P>) | null,
|
|
|
|
children?: RawChildren | RawSlots
|
2019-09-05 23:11:33 +08:00
|
|
|
): VNode
|
|
|
|
|
|
|
|
// fake constructor type returned by `createComponent`
|
2019-09-07 00:58:31 +08:00
|
|
|
export function h(type: Constructor, children?: RawChildren): VNode
|
2019-09-05 23:11:33 +08:00
|
|
|
export function h<P>(
|
|
|
|
type: Constructor<P>,
|
2019-09-07 00:58:31 +08:00
|
|
|
props?: (RawProps & P) | null,
|
|
|
|
children?: RawChildren | RawSlots
|
2019-09-05 23:11:33 +08:00
|
|
|
): VNode
|
|
|
|
|
|
|
|
// Actual implementation
|
2019-08-24 03:27:17 +08:00
|
|
|
export function h(
|
|
|
|
type: VNodeTypes,
|
|
|
|
propsOrChildren?: any,
|
|
|
|
children?: any
|
|
|
|
): VNode {
|
|
|
|
if (arguments.length === 2) {
|
|
|
|
if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
|
|
|
|
// props without children
|
|
|
|
return createVNode(type, propsOrChildren)
|
|
|
|
} else {
|
|
|
|
// omit props
|
|
|
|
return createVNode(type, null, propsOrChildren)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return createVNode(type, propsOrChildren, children)
|
|
|
|
}
|
|
|
|
}
|