Skip to content
24 changes: 24 additions & 0 deletions packages/runtime-core/__tests__/hydration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2357,6 +2357,30 @@ describe('SSR hydration', () => {
expect(`Hydration style mismatch`).not.toHaveBeenWarned()
})

test('with disabled teleport + undefined target', async () => {
const container = document.createElement('div')
const isOpen = ref(false)
const App = {
setup() {
return { isOpen }
},
template: `
<Teleport :to="undefined" :disabled="true">
<div v-if="isOpen">
Menu is open...
</div>
</Teleport>`,
}
container.innerHTML = await renderToString(h(App))
const app = createSSRApp(App)
app.mount(container)
isOpen.value = true
await nextTick()
expect(container.innerHTML).toBe(
`<!--teleport start--><div> Menu is open... </div><!--teleport end-->`,
)
})

test('escape css var name', () => {
const container = document.createElement('div')
container.innerHTML = `<div style="padding: 4px;--foo\\.bar:red;"></div>`
Expand Down
38 changes: 28 additions & 10 deletions packages/runtime-core/src/components/Teleport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,29 +406,43 @@ function hydrateTeleport(
optimized: boolean,
) => Node | null,
): Node | null {
function hydrateDisabledTeleport(
node: Node,
vnode: VNode,
targetStart: Node | null,
targetAnchor: Node | null,
) {
vnode.anchor = hydrateChildren(
nextSibling(node),
vnode,
parentNode(node)!,
parentComponent,
parentSuspense,
slotScopeIds,
optimized,
)
vnode.targetStart = targetStart
vnode.targetAnchor = targetAnchor
}

const target = (vnode.target = resolveTarget<Element>(
vnode.props,
querySelector,
))
const disabled = isTeleportDisabled(vnode.props)
if (target) {
const disabled = isTeleportDisabled(vnode.props)
// if multiple teleports rendered to the same target element, we need to
// pick up from where the last teleport finished instead of the first node
const targetNode =
(target as TeleportTargetElement)._lpa || target.firstChild
if (vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
if (disabled) {
vnode.anchor = hydrateChildren(
nextSibling(node),
hydrateDisabledTeleport(
node,
vnode,
parentNode(node)!,
parentComponent,
parentSuspense,
slotScopeIds,
optimized,
targetNode,
targetNode && nextSibling(targetNode),
)
vnode.targetStart = targetNode
vnode.targetAnchor = targetNode && nextSibling(targetNode)
} else {
vnode.anchor = nextSibling(node)

Expand Down Expand Up @@ -470,6 +484,10 @@ function hydrateTeleport(
}
}
updateCssVars(vnode, disabled)
} else if (disabled) {
if (vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
hydrateDisabledTeleport(node, vnode, node, nextSibling(node))
}
}
return vnode.anchor && nextSibling(vnode.anchor as Node)
}
Expand Down
Loading