// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+exports[`compiler: element transform > MathML 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<math><mrow><mi>x</mi></mrow></math>", true, 2)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
exports[`compiler: element transform > component > cache v-on expression with unique handler name 1`] = `
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
}"
`;
+exports[`compiler: element transform > svg 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<svg><circle r=\\"40\\"></circle></svg>", true, 1)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
exports[`compiler: element transform > v-bind="obj" 1`] = `
"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>", true)
}"
`;
+exports[`compiler v-bind > :class w/ svg elements 1`] = `
+"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
+const t0 = _template("<svg></svg>", true, 1)
+
+export function render(_ctx) {
+ const n0 = t0()
+ _renderEffect(() => _setAttr(n0, "class", _ctx.cls))
+ return n0
+}"
+`;
+
exports[`compiler v-bind > :innerHTML 1`] = `
"import { setHtml as _setHtml, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>", true)
expect(code).toMatchSnapshot()
expect(code).contain('return null')
})
+
+ test('svg', () => {
+ const t = `<svg><circle r="40"></circle></svg>`
+ const { code, ir } = compileWithElementTransform(t)
+ expect(code).toMatchSnapshot()
+ expect(code).contains(
+ '_template("<svg><circle r=\\"40\\"></circle></svg>", true, 1)',
+ )
+ expect(ir.template).toMatchObject([t])
+ expect(ir.templateNS.get(t)).toBe(1)
+ })
+
+ test('MathML', () => {
+ const t = `<math><mrow><mi>x</mi></mrow></math>`
+ const { code, ir } = compileWithElementTransform(t)
+ expect(code).toMatchSnapshot()
+ expect(code).contains(
+ '_template("<math><mrow><mi>x</mi></mrow></math>", true, 2)',
+ )
+ expect(ir.template).toMatchObject([t])
+ expect(ir.templateNS.get(t)).toBe(2)
+ })
})
expect(code).contains('_setProp(n0, "value", _ctx.foo)')
})
+ test(':class w/ svg elements', () => {
+ const { code } = compileWithVBind(`
+ <svg :class="cls"/>
+ `)
+ expect(code).matchSnapshot()
+ expect(code).contains('_setAttr(n0, "class", _ctx.cls))')
+ })
+
test('number value', () => {
const { code } = compileWithVBind(`<Comp :depth="0" />`)
expect(code).matchSnapshot()
modifier: '.' | '^' | undefined,
): HelperConfig {
const tagName = tag.toUpperCase()
+ const isSVG = isSVGTag(tag)
if (modifier) {
if (modifier === '.') {
- return getSpecialHelper(key, tagName) || helpers.setDOMProp
+ return getSpecialHelper(key, tagName, isSVG) || helpers.setDOMProp
} else {
return helpers.setAttr
}
}
// 1. special handling for value / style / class / textContent / innerHTML
- const helper = getSpecialHelper(key, tagName)
+ const helper = getSpecialHelper(key, tagName, isSVG)
if (helper) {
return helper
}
}
// 3. SVG: always attribute
- if (isSVGTag(tag)) {
+ if (isSVG) {
// TODO pass svg flag
return helpers.setAttr
}
function getSpecialHelper(
keyName: string,
tagName: string,
+ isSVG: boolean,
): HelperConfig | undefined {
// special case for 'value' property
if (keyName === 'value' && canSetValueDirectly(tagName)) {
return helpers.setValue
} else if (keyName === 'class') {
- return helpers.setClass
+ return isSVG ? helpers.setAttr : helpers.setClass
} else if (keyName === 'style') {
return helpers.setStyle
} else if (keyName === 'innerHTML') {
--- /dev/null
+describe.todo('MathML support', () => {})
--- /dev/null
+import { makeRender } from '../_utils'
+import { template } from '../../src/dom/template'
+import { child } from '../../src/dom/node'
+import { setAttr, setClass } from '../../src/dom/prop'
+import { renderEffect } from '../../src'
+import { nextTick, ref } from '@vue/runtime-dom'
+
+const define = makeRender()
+
+describe('SVG support', () => {
+ afterEach(() => {
+ document.body.innerHTML = ''
+ })
+
+ test('should mount elements with correct html namespace', () => {
+ define({
+ setup() {
+ const t0 = template(
+ '<div id="e0"><svg id="e1"><foreignObject id="e2"><div id="e3"></div><svg id="e4"></svg><math id="e5"></math></foreignObject></svg></div>',
+ true,
+ )
+ return t0()
+ },
+ }).render()
+
+ const e0 = document.getElementById('e0')!
+ expect(e0.namespaceURI).toMatch('xhtml')
+ expect(e0.querySelector('#e1')!.namespaceURI).toMatch('svg')
+ expect(e0.querySelector('#e2')!.namespaceURI).toMatch('svg')
+ expect(e0.querySelector('#e3')!.namespaceURI).toMatch('xhtml')
+ expect(e0.querySelector('#e4')!.namespaceURI).toMatch('svg')
+ expect(e0.querySelector('#e5')!.namespaceURI).toMatch('Math')
+ })
+
+ test('should patch elements with correct namespaces', async () => {
+ const cls = ref('foo')
+ define({
+ setup() {
+ const t0 = template(
+ '<div><svg id="f1"><foreignObject><div id="f2">hi</div></foreignObject></svg></div>',
+ true,
+ )
+ const n2 = t0() as HTMLElement
+ const n1 = child(n2) as HTMLElement
+ const p0 = child(n1) as HTMLElement
+ const n0 = child(p0) as HTMLElement
+ renderEffect(() => {
+ const _cls = cls.value
+ setAttr(n1, 'class', _cls)
+ setClass(n0, _cls)
+ })
+ return n2
+ },
+ }).render()
+ const f1 = document.querySelector('#f1')!
+ const f2 = document.querySelector('#f2')!
+ expect(f1.getAttribute('class')).toBe('foo')
+ expect(f2.className).toBe('foo')
+
+ cls.value = 'bar'
+ await nextTick()
+ expect(f1.getAttribute('class')).toBe('bar')
+ expect(f2.className).toBe('bar')
+ })
+})