): void
insert(el: HostNode, parent: HostNode, anchor?: HostNode): void
remove(el: HostNode): void
- createElement(type: string): HostNode
+ createElement(type: string, isSVG?: boolean): HostNode
createText(text: string): HostNode
createComment(text: string): HostNode
setText(node: HostNode, text: string): void
n1: VNode | null, // null means this is a mount
n2: VNode,
container: HostNode,
- anchor?: HostNode,
+ anchor: HostNode = null,
+ parentComponent: ComponentInstance | null = null,
+ isSVG: boolean = false,
optimized: boolean = false
) {
// patching & not same type, unmount old tree
processEmptyNode(n1, n2, container, anchor)
break
case Fragment:
- processFragment(n1, n2, container, anchor, optimized)
+ processFragment(
+ n1,
+ n2,
+ container,
+ anchor,
+ parentComponent,
+ isSVG,
+ optimized
+ )
break
case Portal:
- processPortal(n1, n2, container, anchor, optimized)
+ processPortal(
+ n1,
+ n2,
+ container,
+ anchor,
+ parentComponent,
+ isSVG,
+ optimized
+ )
break
default:
if (shapeFlag & ELEMENT) {
- processElement(n1, n2, container, anchor, optimized)
+ processElement(
+ n1,
+ n2,
+ container,
+ anchor,
+ parentComponent,
+ isSVG,
+ optimized
+ )
} else {
if (
__DEV__ &&
// TODO warn invalid node type
debugger
}
- processComponent(n1, n2, container, anchor, optimized)
+ processComponent(
+ n1,
+ n2,
+ container,
+ anchor,
+ parentComponent,
+ isSVG,
+ optimized
+ )
}
break
}
n1: VNode | null,
n2: VNode,
container: HostNode,
- anchor?: HostNode
+ anchor: HostNode
) {
if (n1 == null) {
hostInsert(
n1: VNode | null,
n2: VNode,
container: HostNode,
- anchor?: HostNode
+ anchor: HostNode
) {
if (n1 == null) {
hostInsert((n2.el = hostCreateComment('')), container, anchor)
n1: VNode | null,
n2: VNode,
container: HostNode,
- anchor?: HostNode,
- optimized?: boolean
+ anchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean,
+ optimized: boolean
) {
// mount
if (n1 == null) {
- mountElement(n2, container, anchor)
+ mountElement(n2, container, anchor, parentComponent, isSVG)
} else {
- patchElement(n1, n2, optimized)
+ patchElement(n1, n2, parentComponent, isSVG, optimized)
}
}
- function mountElement(vnode: VNode, container: HostNode, anchor?: HostNode) {
- const el = (vnode.el = hostCreateElement(vnode.type as string))
+ function mountElement(
+ vnode: VNode,
+ container: HostNode,
+ anchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean
+ ) {
+ const tag = vnode.type as string
+ isSVG = isSVG || tag === 'svg'
+ const el = (vnode.el = hostCreateElement(tag, isSVG))
const { props, shapeFlag } = vnode
if (props != null) {
for (const key in props) {
- hostPatchProp(el, key, props[key], null, false)
+ hostPatchProp(el, key, props[key], null, isSVG)
}
}
if (shapeFlag & TEXT_CHILDREN) {
hostSetElementText(el, vnode.children as string)
} else if (shapeFlag & ARRAY_CHILDREN) {
- mountChildren(vnode.children as VNodeChildren, el)
+ mountChildren(
+ vnode.children as VNodeChildren,
+ el,
+ null,
+ parentComponent,
+ isSVG
+ )
}
hostInsert(el, container, anchor)
}
function mountChildren(
children: VNodeChildren,
container: HostNode,
- anchor?: HostNode,
+ anchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean,
start: number = 0
) {
for (let i = start; i < children.length; i++) {
const child = (children[i] = normalizeVNode(children[i]))
- patch(null, child, container, anchor)
+ patch(null, child, container, anchor, parentComponent, isSVG)
}
}
- function patchElement(n1: VNode, n2: VNode, optimized?: boolean) {
+ function patchElement(
+ n1: VNode,
+ n2: VNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean,
+ optimized: boolean
+ ) {
const el = (n2.el = n1.el)
const { patchFlag, dynamicChildren } = n2
const oldProps = (n1 && n1.props) || EMPTY_OBJ
if (patchFlag & FULL_PROPS) {
// element props contain dynamic keys, full diff needed
- patchProps(el, n2, oldProps, newProps)
+ patchProps(el, n2, oldProps, newProps, isSVG)
} else {
// class
// this flag is matched when the element has dynamic class bindings.
if (patchFlag & CLASS) {
if (oldProps.class !== newProps.class) {
- hostPatchProp(el, 'class', newProps.class, null, false)
+ hostPatchProp(el, 'class', newProps.class, null, isSVG)
}
}
// this flag is matched when the element has dynamic style bindings
// TODO separate static and dynamic styles?
if (patchFlag & STYLE) {
- hostPatchProp(el, 'style', newProps.style, oldProps.style, false)
+ hostPatchProp(el, 'style', newProps.style, oldProps.style, isSVG)
}
// props
key,
next,
prev,
- false,
+ isSVG,
n1.children as VNode[],
unmountChildren
)
}
} else if (!optimized) {
// unoptimized, full diff
- patchProps(el, n2, oldProps, newProps)
+ patchProps(el, n2, oldProps, newProps, isSVG)
}
if (dynamicChildren != null) {
// children fast path
const olddynamicChildren = n1.dynamicChildren as VNode[]
for (let i = 0; i < dynamicChildren.length; i++) {
- patch(olddynamicChildren[i], dynamicChildren[i], el, null, true)
+ patch(
+ olddynamicChildren[i],
+ dynamicChildren[i],
+ el,
+ null,
+ parentComponent,
+ isSVG,
+ true
+ )
}
} else if (!optimized) {
// full diff
- patchChildren(n1, n2, el)
+ patchChildren(n1, n2, el, null, parentComponent, isSVG)
}
}
el: HostNode,
vnode: VNode,
oldProps: any,
- newProps: any
+ newProps: any,
+ isSVG: boolean
) {
if (oldProps !== newProps) {
for (const key in newProps) {
key,
next,
prev,
- false,
+ isSVG,
vnode.children as VNode[],
unmountChildren
)
key,
null,
null,
- false,
+ isSVG,
vnode.children as VNode[],
unmountChildren
)
n1: VNode | null,
n2: VNode,
container: HostNode,
- anchor?: HostNode,
- optimized?: boolean
+ anchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean,
+ optimized: boolean
) {
const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateComment(''))
const fragmentEndAnchor = (n2.anchor = n1
hostInsert(fragmentStartAnchor, container, anchor)
hostInsert(fragmentEndAnchor, container, anchor)
// a fragment can only have array children
- mountChildren(n2.children as VNodeChildren, container, fragmentEndAnchor)
+ mountChildren(
+ n2.children as VNodeChildren,
+ container,
+ fragmentEndAnchor,
+ parentComponent,
+ isSVG
+ )
} else {
- patchChildren(n1, n2, container, fragmentEndAnchor, optimized)
+ patchChildren(
+ n1,
+ n2,
+ container,
+ fragmentEndAnchor,
+ parentComponent,
+ isSVG,
+ optimized
+ )
}
}
n1: VNode | null,
n2: VNode,
container: HostNode,
- anchor?: HostNode,
- optimized?: boolean
+ anchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean,
+ optimized: boolean
) {
const targetSelector = n2.props && n2.props.target
const { patchFlag, shapeFlag, children } = n2
if (shapeFlag & TEXT_CHILDREN) {
hostSetElementText(target, children as string)
} else if (shapeFlag & ARRAY_CHILDREN) {
- mountChildren(children as VNodeChildren, target)
+ mountChildren(
+ children as VNodeChildren,
+ target,
+ null,
+ parentComponent,
+ isSVG
+ )
}
} else {
// TODO warn missing or invalid target
if (patchFlag === TEXT) {
hostSetElementText(target, children as string)
} else if (!optimized) {
- patchChildren(n1, n2, target)
+ patchChildren(n1, n2, target, null, parentComponent, isSVG)
}
// target changed
if (targetSelector !== (n1.props && n1.props.target)) {
n1: VNode | null,
n2: VNode,
container: HostNode,
- anchor?: HostNode,
- optimized?: boolean
+ anchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean,
+ optimized: boolean
) {
if (n1 == null) {
- mountComponent(n2, container, anchor)
+ mountComponent(n2, container, anchor, parentComponent, isSVG)
} else {
const instance = (n2.component = n1.component) as ComponentInstance
if (shouldUpdateComponent(n1, n2, optimized)) {
function mountComponent(
vnode: VNode,
container: HostNode,
- anchor?: HostNode
+ anchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean
) {
const Component = vnode.type as any
const instance: ComponentInstance = (vnode.component = createComponentInstance(
- Component
+ Component,
+ parentComponent
))
instance.update = effect(function updateComponent() {
if (instance.vnode === null) {
if (instance.bm !== null) {
invokeHooks(instance.bm)
}
- patch(null, subTree, container, anchor)
+ patch(null, subTree, container, anchor, instance, isSVG)
vnode.el = subTree.el
// mounted hook
if (instance.m !== null) {
// This is triggered by mutation of component's own state (next: null)
// OR parent calling processComponent (next: VNode)
const { next } = instance
- if (next != null) {
+ if (next !== null) {
next.component = instance
instance.vnode = next
instance.next = null
nextTree,
// may have moved
hostParentNode(prevTree.el),
- getNextHostNode(prevTree)
+ getNextHostNode(prevTree),
+ instance,
+ isSVG
)
- if (next != null) {
+ if (next !== null) {
next.el = nextTree.el
+ } else {
+ // TODO in case of HOC, update parent component vnode el
}
// upated hook
if (instance.u !== null) {
n1: VNode | null,
n2: VNode,
container: HostNode,
- anchor?: HostNode,
- optimized?: boolean
+ anchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean,
+ optimized: boolean = false
) {
const c1 = n1 && n1.children
const prevShapeFlag = n1 ? n1.shapeFlag : 0
c2 as VNodeChildren,
container,
anchor,
+ parentComponent,
+ isSVG,
optimized
)
return
c2 as VNodeChildren,
container,
anchor,
+ parentComponent,
+ isSVG,
optimized
)
return
if (prevShapeFlag & TEXT_CHILDREN) {
hostSetElementText(container, '')
if (shapeFlag & ARRAY_CHILDREN) {
- mountChildren(c2 as VNodeChildren, container, anchor)
+ mountChildren(
+ c2 as VNodeChildren,
+ container,
+ anchor,
+ parentComponent,
+ isSVG
+ )
}
} else if (prevShapeFlag & ARRAY_CHILDREN) {
if (shapeFlag & ARRAY_CHILDREN) {
c2 as VNodeChildren,
container,
anchor,
+ parentComponent,
+ isSVG,
optimized
)
} else {
c1: VNode[],
c2: VNodeChildren,
container: HostNode,
- anchor?: HostNode,
- optimized?: boolean
+ anchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean,
+ optimized: boolean
) {
c1 = c1 || EMPTY_ARR
c2 = c2 || EMPTY_ARR
let i
for (i = 0; i < commonLength; i++) {
const nextChild = (c2[i] = normalizeVNode(c2[i]))
- patch(c1[i], nextChild, container, null, optimized)
+ patch(
+ c1[i],
+ nextChild,
+ container,
+ null,
+ parentComponent,
+ isSVG,
+ optimized
+ )
}
if (oldLength > newLength) {
// remove old
unmountChildren(c1, true, commonLength)
} else {
// mount new
- mountChildren(c2, container, anchor, commonLength)
+ mountChildren(c2, container, anchor, parentComponent, isSVG, commonLength)
}
}
c1: VNode[],
c2: VNodeChildren,
container: HostNode,
- parentAnchor?: HostNode,
- optimized?: boolean
+ parentAnchor: HostNode,
+ parentComponent: ComponentInstance | null,
+ isSVG: boolean,
+ optimized: boolean
) {
let i = 0
const l2 = c2.length
const n1 = c1[i]
const n2 = (c2[i] = normalizeVNode(c2[i]))
if (isSameType(n1, n2)) {
- patch(n1, n2, container, parentAnchor, optimized)
+ patch(
+ n1,
+ n2,
+ container,
+ parentAnchor,
+ parentComponent,
+ isSVG,
+ optimized
+ )
} else {
break
}
const n1 = c1[e1]
const n2 = (c2[e2] = normalizeVNode(c2[e2]))
if (isSameType(n1, n2)) {
- patch(n1, n2, container, parentAnchor, optimized)
+ patch(
+ n1,
+ n2,
+ container,
+ parentAnchor,
+ parentComponent,
+ isSVG,
+ optimized
+ )
} else {
break
}
const nextPos = e2 + 1
const anchor = nextPos < l2 ? (c2[nextPos] as VNode).el : parentAnchor
while (i <= e2) {
- patch(null, (c2[i] = normalizeVNode(c2[i])), container, anchor)
+ patch(
+ null,
+ (c2[i] = normalizeVNode(c2[i])),
+ container,
+ anchor,
+ parentComponent,
+ isSVG
+ )
i++
}
}
} else {
moved = true
}
- patch(prevChild, c2[newIndex] as VNode, container, null, optimized)
+ patch(
+ prevChild,
+ c2[newIndex] as VNode,
+ container,
+ null,
+ parentComponent,
+ isSVG,
+ optimized
+ )
patched++
}
}
nextIndex + 1 < l2 ? (c2[nextIndex + 1] as VNode).el : parentAnchor
if (newIndexToOldIndexMap[i] === 0) {
// mount new
- patch(null, nextChild, container, anchor)
+ patch(null, nextChild, container, anchor, parentComponent, isSVG)
} else if (moved) {
// move if:
// There is no stable subsequence (e.g. a reverse)