Skip to content

Commit

Permalink
fix(teleport): Teleport into SVG elements (#2648)
Browse files Browse the repository at this point in the history
fix #2652
  • Loading branch information
yassilah committed Nov 30, 2020
1 parent 7a1a782 commit cd92836
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
36 changes: 34 additions & 2 deletions packages/runtime-core/__tests__/components/Teleport.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import {
Text,
ref,
nextTick,
markRaw
markRaw,
defineComponent
} from '@vue/runtime-test'
import { createVNode, Fragment } from '../../src/vnode'
import { compile } from 'vue'
import { compile, render as domRender } from 'vue'

describe('renderer: teleport', () => {
test('should work', () => {
Expand All @@ -33,6 +34,37 @@ describe('renderer: teleport', () => {
)
})

test('should work with SVG', async () => {
const root = document.createElement('div')
const svg = ref()
const circle = ref()

const Comp = defineComponent({
setup() {
return {
svg,
circle
}
},
template: `
<svg ref="svg"></svg>
<teleport :to="svg" v-if="svg">
<circle ref="circle"></circle>
</teleport>`
})

domRender(h(Comp), root)

await nextTick()

expect(root.innerHTML).toMatchInlineSnapshot(
`"<svg><circle></circle></svg><!--teleport start--><!--teleport end-->"`
)

expect(svg.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
expect(circle.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
})

test('should update target', async () => {
const targetA = nodeOps.createElement('div')
const targetB = nodeOps.createElement('div')
Expand Down
8 changes: 7 additions & 1 deletion packages/runtime-core/src/components/Teleport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export const isTeleport = (type: any): boolean => type.__isTeleport
export const isTeleportDisabled = (props: VNode['props']): boolean =>
props && (props.disabled || props.disabled === '')

const isTargetSVG = (target: RendererElement): boolean =>
typeof SVGElement !== 'undefined' && target instanceof SVGElement

const resolveTarget = <T = RendererElement>(
props: TeleportProps | null,
select: RendererOptions['querySelector']
Expand Down Expand Up @@ -80,6 +83,7 @@ export const TeleportImpl = {

const disabled = isTeleportDisabled(n2.props)
const { shapeFlag, children } = n2

if (n1 == null) {
// insert anchors in the main view
const placeholder = (n2.el = __DEV__
Expand All @@ -90,11 +94,12 @@ export const TeleportImpl = {
: createText(''))
insert(placeholder, container, anchor)
insert(mainAnchor, container, anchor)

const target = (n2.target = resolveTarget(n2.props, querySelector))
const targetAnchor = (n2.targetAnchor = createText(''))
if (target) {
insert(targetAnchor, target)
// #2652 we could be teleporting from a non-SVG tree into an SVG tree
isSVG = isSVG || isTargetSVG(target)
} else if (__DEV__ && !disabled) {
warn('Invalid Teleport target on mount:', target, `(${typeof target})`)
}
Expand Down Expand Up @@ -129,6 +134,7 @@ export const TeleportImpl = {
const wasDisabled = isTeleportDisabled(n1.props)
const currentContainer = wasDisabled ? container : target
const currentAnchor = wasDisabled ? mainAnchor : targetAnchor
isSVG = isSVG || isTargetSVG(target)

if (n2.dynamicChildren) {
// fast path when the teleport happens to be a block root
Expand Down

0 comments on commit cd92836

Please sign in to comment.