unmount(vnode: VNode, doRemove?: boolean): void
move(vnode: VNode, container: any, anchor: any): void
slot(n1: VNode | null, n2: VNode, container: any, anchor: any): void
+ activate(
+ vnode: VNode,
+ container: any,
+ anchor: any,
+ parentComponent: ComponentInternalInstance,
+ ): void
+ deactivate(vnode: VNode, container: any): void
vdomMount: (component: ConcreteComponent, props?: any, slots?: any) => any
vdomUnmount: UnmountComponentFn
optimized: boolean,
) => void
deactivate: (vnode: VNode) => void
+ getCachedComponent: (vnode: VNode) => VNode
+ getStorageContainer: () => RendererElement
}
export const isKeepAlive = (vnode: any): boolean =>
} = renderer
const storageContainer = createElement('div')
+ sharedContext.getStorageContainer = () => storageContainer
+
+ sharedContext.getCachedComponent = (vnode: VNode) => {
+ const key =
+ vnode.key == null ? (vnode.type as ConcreteComponent) : vnode.key
+ return cache.get(key)!
+ }
+
sharedContext.activate = (
vnode,
container,
if ((n2.type as ConcreteComponent).__vapor) {
if (n1 == null) {
- getVaporInterface(parentComponent, n2).mount(
- n2,
- container,
- anchor,
- parentComponent,
- )
+ if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
+ getVaporInterface(parentComponent, n2).activate(
+ n2,
+ container,
+ anchor,
+ parentComponent!,
+ )
+ } else {
+ getVaporInterface(parentComponent, n2).mount(
+ n2,
+ container,
+ anchor,
+ parentComponent,
+ )
+ }
} else {
getVaporInterface(parentComponent, n2).update(
n1,
}
if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
- ;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)
+ if ((vnode.type as ConcreteComponent).__vapor) {
+ getVaporInterface(parentComponent!, vnode).deactivate(
+ vnode,
+ (parentComponent!.ctx as KeepAliveContext).getStorageContainer(),
+ )
+ } else {
+ ;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)
+ }
return
}
const getNextHostNode: NextFn = vnode => {
if (vnode.shapeFlag & ShapeFlags.COMPONENT) {
if ((vnode.type as ConcreteComponent).__vapor) {
- return hostNextSibling((vnode.component! as any).block)
+ return hostNextSibling(vnode.anchor!)
}
return getNextHostNode(vnode.component!.subTree)
}
}
function locateNonHydratedAsyncRoot(
- instance: ComponentInternalInstance,
+ instance: GenericComponentInstance,
): ComponentInternalInstance | undefined {
- const subComponent = instance.subTree.component
+ const subComponent = instance.vapor
+ ? null
+ : (instance as ComponentInternalInstance).subTree.component
if (subComponent) {
if (subComponent.asyncDep && !subComponent.asyncResolved) {
return subComponent
locateHydrationNode()
}
- // try to get the cached instance if inside keep-alive
- if (currentInstance && isKeepAlive(currentInstance)) {
+ // keep-alive
+ if (
+ currentInstance &&
+ currentInstance.vapor &&
+ isKeepAlive(currentInstance)
+ ) {
const cached = (currentInstance as KeepAliveInstance).getCachedComponent(
component,
)
- if (cached) return cached as any
+ // @ts-expect-error cached may be a fragment
+ if (cached) return cached
}
// vdom interop enabled and component is not an explicit vapor component
rawProps,
rawSlots,
)
+ // TODO: problem is `frag.insert` will be called multiple times
+ // if used in v-if
if (!isHydrating && _insertionParent) {
insert(frag, _insertionParent, _insertionAnchor)
}
instance: VaporComponentInstance,
parentNode?: ParentNode,
): void {
- if (instance.shapeFlag! & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
+ if (
+ parentNode &&
+ instance.parent &&
+ instance.parent.vapor &&
+ instance.shapeFlag! & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
+ ) {
;(instance.parent as KeepAliveInstance).deactivate(instance)
return
}
keepAliveInstance.activate = (instance, parentNode, anchor) => {
current = instance
- insert(instance.block, parentNode, anchor)
-
- queuePostFlushCb(() => {
- instance.isDeactivated = false
- if (instance.a) invokeArrayFns(instance.a)
- })
-
- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
- devtoolsComponentAdded(instance)
- }
+ activate(instance, parentNode, anchor)
}
keepAliveInstance.deactivate = instance => {
- insert(instance.block, storageContainer)
-
- queuePostFlushCb(() => {
- if (instance.da) invokeArrayFns(instance.da)
- instance.isDeactivated = true
- })
-
- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
- devtoolsComponentAdded(instance)
- }
+ deactivate(instance, storageContainer)
}
let children = slots.default()
function isVdomInteropFragment(block: Block): block is VaporFragment {
return !!(isFragment(block) && block.insert)
}
+
+export function activate(
+ instance: VaporComponentInstance,
+ parentNode: ParentNode,
+ anchor?: Node | null | 0,
+): void {
+ insert(instance.block, parentNode, anchor)
+
+ queuePostFlushCb(() => {
+ instance.isDeactivated = false
+ if (instance.a) invokeArrayFns(instance.a)
+ })
+
+ if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
+ devtoolsComponentAdded(instance)
+ }
+}
+
+export function deactivate(
+ instance: VaporComponentInstance,
+ container: ParentNode,
+): void {
+ insert(instance.block, container)
+
+ queuePostFlushCb(() => {
+ if (instance.da) invokeArrayFns(instance.da)
+ instance.isDeactivated = true
+ })
+
+ if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
+ devtoolsComponentAdded(instance)
+ }
+}
type Slots,
type VNode,
type VaporInteropInterface,
- activate,
createVNode,
currentInstance,
- deactivate,
ensureRenderer,
+ isKeepAlive,
onScopeDispose,
renderSlot,
shallowRef,
simpleSetCurrentInstance,
+ activate as vdomActivate,
+ deactivate as vdomDeactivate,
} from '@vue/runtime-dom'
import {
type LooseRawProps,
import { renderEffect } from './renderEffect'
import { createTextNode } from './dom/node'
import { optimizePropertyLookup } from './dom/prop'
-import type { KeepAliveInstance } from './components/KeepAlive'
+import {
+ type KeepAliveInstance,
+ activate,
+ deactivate,
+} from './components/KeepAlive'
+import type { KeepAliveContext } from 'packages/runtime-core/src/components/KeepAlive'
// mounting vapor components and slots in vdom
const vaporInteropImpl: Omit<
))
instance.rawPropsRef = propsRef
instance.rawSlotsRef = slotsRef
+ // copy the shape flag from the vdom component if inside a keep-alive
+ if (isKeepAlive(parentComponent)) instance.shapeFlag = vnode.shapeFlag
mountComponent(instance, container, selfAnchor)
simpleSetCurrentInstance(prev)
return instance
insert(vnode.vb || (vnode.component as any), container, anchor)
insert(vnode.anchor as any, container, anchor)
},
+
+ activate(vnode, container, anchor, parentComponent) {
+ const cached = (parentComponent.ctx as KeepAliveContext).getCachedComponent(
+ vnode,
+ )
+
+ vnode.el = cached.el
+ vnode.component = cached.component
+ vnode.anchor = cached.anchor
+ activate(vnode.component as any, container, anchor)
+ insert(vnode.anchor as any, container, anchor)
+ },
+
+ deactivate(vnode, container) {
+ deactivate(vnode.component as any, container)
+ insert(vnode.anchor as any, container)
+ },
}
const vaporSlotPropsProxyHandler: ProxyHandler<
const parentInstance = currentInstance as VaporComponentInstance
const unmount = (parentNode?: ParentNode) => {
if (vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
- deactivate(
+ vdomDeactivate(
vnode,
(parentInstance as KeepAliveInstance).getStorageContainer(),
internals,
frag.insert = (parentNode, anchor) => {
if (vnode.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
- activate(
+ vdomActivate(
vnode,
parentNode,
anchor,