import { hmrReload, hmrRerender } from './hmr'
import { isHydrating, locateHydrationNode } from './dom/hydration'
import { insertionAnchor, insertionParent } from './insertionState'
-import type { VaporTeleportImpl } from './components/Teleport'
+import {
+ type VaporTeleportImpl,
+ instanceToTeleportMap,
+ teleportStack,
+} from './components/Teleport'
export { currentInstance } from '@vue/runtime-dom'
)
if (__DEV__) {
+ let teleport = teleportStack[teleportStack.length - 1]
+ if (teleport) {
+ instanceToTeleportMap.set(instance, teleport)
+ }
+
pushWarningContext(instance)
startMeasure(instance, `init`)
onScopeDispose(() => unmountComponent(instance), true)
if (!isHydrating && _insertionParent) {
- insert(instance.block, _insertionParent, _insertionAnchor)
+ mountComponent(instance, _insertionParent, _insertionAnchor)
}
return instance
remove,
} from '../block'
import { createComment, createTextNode, querySelector } from '../dom/node'
-import type { LooseRawProps, LooseRawSlots } from '../component'
+import type {
+ LooseRawProps,
+ LooseRawSlots,
+ VaporComponentInstance,
+} from '../component'
import { rawPropsProxyHandlers } from '../componentProps'
import { renderEffect } from '../renderEffect'
-import { extend } from '@vue/shared'
+import { extend, isArray } from '@vue/shared'
import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
+export const teleportStack: TeleportFragment[] = []
+export const instanceToTeleportMap: WeakMap<
+ VaporComponentInstance,
+ TeleportFragment
+> = __DEV__ ? new WeakMap() : (null as any)
+
+/**
+ * dev only.
+ * when the **root** child component updates, synchronously update
+ * the TeleportFragment's children and nodes.
+ */
+export function handleTeleportChildrenHmrReload(
+ instance: VaporComponentInstance,
+ newInstance: VaporComponentInstance,
+): void {
+ const teleport = instanceToTeleportMap.get(instance)
+ if (teleport) {
+ instanceToTeleportMap.set(newInstance, teleport)
+ if (teleport.nodes === instance) {
+ teleport.children = teleport.nodes = newInstance
+ } else if (isArray(teleport.nodes)) {
+ const i = teleport.nodes.indexOf(instance)
+ if (i > -1) {
+ ;(teleport.children as Block[])[i] = teleport.nodes[i] = newInstance
+ }
+ }
+ }
+}
+
export const VaporTeleportImpl = {
name: 'VaporTeleport',
__isTeleport: true,
pauseTracking()
const scope = (frag.scope = new EffectScope())
scope!.run(() => {
- let children: Block
renderEffect(() => {
+ teleportStack.push(frag)
frag.updateChildren(
- (children = slots.default && (slots.default as BlockFn)()),
+ (frag.children = slots.default && (slots.default as BlockFn)()),
)
+ teleportStack.pop()
})
renderEffect(() => {
{},
new Proxy(props, rawPropsProxyHandlers) as any as TeleportProps,
),
- children!,
+ frag.children!,
)
})
})
resetTracking()
if (__DEV__) {
- // TODO
- ;(frag as any).getNodes = () => {
+ // used in normalizeBlock to get the nodes of a TeleportFragment
+ // during hmr update. return empty array if the teleport content
+ // is mounted into the target container.
+ frag.getNodes = () => {
return frag.parent !== frag.currentParent ? [] : frag.nodes
}
}
class TeleportFragment extends VaporFragment {
anchor: Node
scope: EffectScope | undefined
+ children: Block | undefined
private targetStart?: Node
private mainAnchor?: Node
// remove nodes
if (this.nodes) {
remove(this.nodes, this.currentParent)
- this.nodes = []
+ this.children = this.nodes = []
}
// remove anchors