2018-09-19 23:35:38 +08:00
|
|
|
import { ChildrenFlags } from './flags'
|
|
|
|
import { ComponentClass, FunctionalComponent } from './component'
|
|
|
|
import { ComponentOptions } from './componentOptions'
|
|
|
|
import {
|
|
|
|
VNode,
|
|
|
|
createElementVNode,
|
|
|
|
createComponentVNode,
|
|
|
|
createTextVNode,
|
|
|
|
createFragment,
|
|
|
|
createPortal
|
|
|
|
} from './vdom'
|
2018-10-05 04:13:02 +08:00
|
|
|
import { isObservable, unwrap } from '@vue/observer'
|
2018-09-19 23:35:38 +08:00
|
|
|
|
|
|
|
export const Fragment = Symbol()
|
|
|
|
export const Portal = Symbol()
|
|
|
|
|
|
|
|
type ElementType =
|
|
|
|
| string
|
|
|
|
| FunctionalComponent
|
|
|
|
| ComponentClass
|
|
|
|
| ComponentOptions
|
|
|
|
| typeof Fragment
|
|
|
|
| typeof Portal
|
|
|
|
|
|
|
|
export interface createElement {
|
2018-09-20 09:51:21 +08:00
|
|
|
(tag: ElementType, data?: any, children?: any): VNode
|
2018-09-19 23:35:38 +08:00
|
|
|
c: typeof createComponentVNode
|
|
|
|
e: typeof createElementVNode
|
|
|
|
t: typeof createTextVNode
|
|
|
|
f: typeof createFragment
|
|
|
|
p: typeof createPortal
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
// so that we can mutate it later on.
|
|
|
|
if (isObservable(data)) {
|
|
|
|
data = Object.assign({}, unwrap(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-09-27 06:34:21 +08:00
|
|
|
console.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-09-27 06:34:21 +08:00
|
|
|
console.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'))
|
|
|
|
) {
|
|
|
|
console.warn('Invalid component passed to h(): ', tag)
|
|
|
|
}
|
2018-09-19 23:35:38 +08:00
|
|
|
// component
|
|
|
|
return createComponentVNode(
|
|
|
|
tag,
|
|
|
|
data,
|
|
|
|
children,
|
|
|
|
ChildrenFlags.UNKNOWN_CHILDREN,
|
|
|
|
key,
|
|
|
|
ref
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}) as createElement
|
|
|
|
|
|
|
|
h.c = createComponentVNode
|
|
|
|
h.e = createElementVNode
|
|
|
|
h.t = createTextVNode
|
|
|
|
h.f = createFragment
|
|
|
|
h.p = createPortal
|