2018-09-19 23:35:38 +08:00
|
|
|
import { ChildrenFlags } from './flags'
|
2018-10-13 01:42:19 +08:00
|
|
|
import {
|
|
|
|
ComponentClass,
|
|
|
|
FunctionalComponent,
|
|
|
|
Component,
|
|
|
|
ComponentInstance
|
|
|
|
} from './component'
|
2018-09-19 23:35:38 +08:00
|
|
|
import { ComponentOptions } from './componentOptions'
|
|
|
|
import {
|
|
|
|
VNode,
|
|
|
|
createElementVNode,
|
|
|
|
createComponentVNode,
|
|
|
|
createTextVNode,
|
|
|
|
createFragment,
|
2018-10-13 01:42:19 +08:00
|
|
|
createPortal,
|
|
|
|
VNodeData,
|
|
|
|
BuiltInProps
|
2018-09-19 23:35:38 +08:00
|
|
|
} from './vdom'
|
2018-10-10 09:10:30 +08:00
|
|
|
import { isObservable } from '@vue/observer'
|
2018-10-12 05:21:13 +08:00
|
|
|
import { warn } from './warning'
|
2018-09-19 23:35:38 +08:00
|
|
|
|
|
|
|
export const Fragment = Symbol()
|
|
|
|
export const Portal = Symbol()
|
|
|
|
|
2018-10-13 01:42:19 +08:00
|
|
|
export type ElementType =
|
2018-09-19 23:35:38 +08:00
|
|
|
| string
|
|
|
|
| FunctionalComponent
|
|
|
|
| ComponentClass
|
|
|
|
| ComponentOptions
|
|
|
|
| typeof Fragment
|
|
|
|
| typeof Portal
|
|
|
|
|
2018-10-13 01:42:19 +08:00
|
|
|
type RawChildType = VNode | string | number | boolean | null | undefined
|
|
|
|
|
|
|
|
export type RawChildrenType = RawChildType | RawChildType[]
|
|
|
|
|
|
|
|
interface VNodeFactories {
|
2018-09-19 23:35:38 +08:00
|
|
|
c: typeof createComponentVNode
|
|
|
|
e: typeof createElementVNode
|
|
|
|
t: typeof createTextVNode
|
|
|
|
f: typeof createFragment
|
|
|
|
p: typeof createPortal
|
|
|
|
}
|
|
|
|
|
2018-10-13 01:42:19 +08:00
|
|
|
interface createElement {
|
|
|
|
// element
|
|
|
|
(tag: string, data?: VNodeData, children?: any): VNode
|
|
|
|
// functional
|
|
|
|
<P>(
|
|
|
|
tag: FunctionalComponent<P>,
|
|
|
|
data?: P & BuiltInProps | null,
|
|
|
|
children?: any
|
|
|
|
): VNode
|
|
|
|
// stateful
|
|
|
|
<P, T extends ComponentInstance<P>>(
|
|
|
|
tag: new () => T & { $props: P },
|
|
|
|
data?: P & BuiltInProps | null,
|
|
|
|
children?: any
|
|
|
|
): VNode
|
|
|
|
}
|
|
|
|
|
2018-09-20 09:51:21 +08:00
|
|
|
export const h = ((tag: ElementType, data?: any, children?: any): VNode => {
|
2018-09-26 05:49:47 +08:00
|
|
|
if (
|
|
|
|
Array.isArray(data) ||
|
|
|
|
(data != null && (typeof data !== 'object' || data._isVNode))
|
|
|
|
) {
|
2018-09-19 23:35:38 +08:00
|
|
|
children = data
|
|
|
|
data = null
|
|
|
|
}
|
|
|
|
|
2018-09-25 07:11:14 +08:00
|
|
|
if (data === void 0) data = null
|
|
|
|
if (children === void 0) children = null
|
|
|
|
|
2018-10-05 04:13:02 +08:00
|
|
|
// if value is observable, create a clone of original
|
2018-10-10 09:10:30 +08:00
|
|
|
// so that we can normalize its class/style
|
2018-10-05 04:13:02 +08:00
|
|
|
if (isObservable(data)) {
|
2018-10-10 09:10:30 +08:00
|
|
|
data = Object.assign({}, data)
|
2018-09-25 07:11:14 +08:00
|
|
|
}
|
2018-09-19 23:35:38 +08:00
|
|
|
|
|
|
|
let key = null
|
|
|
|
let ref = null
|
|
|
|
let portalTarget = null
|
|
|
|
if (data != null) {
|
|
|
|
if (data.slots != null) {
|
|
|
|
children = data.slots
|
|
|
|
}
|
|
|
|
if (data.key != null) {
|
|
|
|
;({ key } = data)
|
|
|
|
}
|
|
|
|
if (data.ref != null) {
|
|
|
|
;({ ref } = data)
|
|
|
|
}
|
|
|
|
if (data.target != null) {
|
|
|
|
portalTarget = data.target
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof tag === 'string') {
|
|
|
|
// element
|
|
|
|
return createElementVNode(
|
|
|
|
tag,
|
|
|
|
data,
|
|
|
|
children,
|
|
|
|
ChildrenFlags.UNKNOWN_CHILDREN,
|
|
|
|
key,
|
|
|
|
ref
|
|
|
|
)
|
|
|
|
} else if (tag === Fragment) {
|
|
|
|
if (__DEV__ && ref) {
|
2018-10-12 05:21:13 +08:00
|
|
|
warn('Ref cannot be used on Fragments. Use it on inner elements instead.')
|
2018-09-19 23:35:38 +08:00
|
|
|
}
|
|
|
|
return createFragment(children, ChildrenFlags.UNKNOWN_CHILDREN, key)
|
|
|
|
} else if (tag === Portal) {
|
|
|
|
if (__DEV__ && !portalTarget) {
|
2018-10-12 05:21:13 +08:00
|
|
|
warn('Portal must have a target: ', portalTarget)
|
2018-09-19 23:35:38 +08:00
|
|
|
}
|
|
|
|
return createPortal(
|
|
|
|
portalTarget,
|
|
|
|
children,
|
|
|
|
ChildrenFlags.UNKNOWN_CHILDREN,
|
|
|
|
key,
|
|
|
|
ref
|
|
|
|
)
|
|
|
|
} else {
|
2018-09-27 06:34:21 +08:00
|
|
|
if (
|
|
|
|
__DEV__ &&
|
|
|
|
(!tag || (typeof tag !== 'function' && typeof tag !== 'object'))
|
|
|
|
) {
|
2018-10-12 05:21:13 +08:00
|
|
|
warn('Invalid component passed to h(): ', tag)
|
2018-09-27 06:34:21 +08:00
|
|
|
}
|
2018-09-19 23:35:38 +08:00
|
|
|
// component
|
|
|
|
return createComponentVNode(
|
|
|
|
tag,
|
|
|
|
data,
|
|
|
|
children,
|
|
|
|
ChildrenFlags.UNKNOWN_CHILDREN,
|
|
|
|
key,
|
|
|
|
ref
|
|
|
|
)
|
|
|
|
}
|
2018-10-13 01:42:19 +08:00
|
|
|
}) as createElement & VNodeFactories
|
2018-09-19 23:35:38 +08:00
|
|
|
|
|
|
|
h.c = createComponentVNode
|
|
|
|
h.e = createElementVNode
|
|
|
|
h.t = createTextVNode
|
|
|
|
h.f = createFragment
|
|
|
|
h.p = createPortal
|