Skip to content

Commit 1403064

Browse files
Merge pull request #310 from preactjs/xml-namespaces
2 parents 2eb96be + 017a8bb commit 1403064

File tree

3 files changed

+25
-8
lines changed

3 files changed

+25
-8
lines changed

.changeset/five-stingrays-return.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'preact-render-to-string': patch
3+
---
4+
5+
Fix casing of namespaced attribute names

src/index.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { encodeEntities, styleObjToCss, UNSAFE_NAME, XLINK } from './util.js';
1+
import { encodeEntities, styleObjToCss, UNSAFE_NAME } from './util.js';
22
import { options, h, Fragment } from 'preact';
33
import {
44
CHILDREN,
@@ -392,8 +392,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
392392
break;
393393

394394
default: {
395-
if (isSvgMode && XLINK.test(name)) {
396-
name = name.toLowerCase().replace(XLINK_REPLACE_REGEX, 'xlink:');
395+
if (NAMESPACE_REPLACE_REGEX.test(name)) {
396+
name = name.replace(NAMESPACE_REPLACE_REGEX, '$1:$2').toLowerCase();
397397
} else if (UNSAFE_NAME.test(name)) {
398398
continue;
399399
} else if ((name[4] === '-' || name === 'draggable') && v != null) {
@@ -407,8 +407,6 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
407407
name === 'panose1'
408408
? 'panose-1'
409409
: name.replace(/([A-Z])/g, '-$1').toLowerCase();
410-
} else if (XML_REPLACE_REGEX.test(name)) {
411-
name = name.toLowerCase().replace(XML_REPLACE_REGEX, 'xml:');
412410
}
413411
} else if (HTML_LOWER_CASE.test(name)) {
414412
name = name.toLowerCase();
@@ -458,8 +456,7 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
458456

459457
const HTML_LOWER_CASE = /^accessK|^auto[A-Z]|^ch|^col|cont|cross|dateT|encT|form[A-Z]|frame|hrefL|inputM|maxL|minL|noV|playsI|readO|rowS|spellC|src[A-Z]|tabI|item[A-Z]/;
460458
const SVG_CAMEL_CASE = /^ac|^ali|arabic|basel|cap|clipPath$|clipRule$|color|dominant|enable|fill|flood|font|glyph[^R]|horiz|image|letter|lighting|marker[^WUH]|overline|panose|pointe|paint|rendering|shape|stop|strikethrough|stroke|text[^L]|transform|underline|unicode|units|^v[^i]|^w|^xH/;
461-
const XML_REPLACE_REGEX = /^xml:?/;
462-
const XLINK_REPLACE_REGEX = /^xlink:?/;
459+
const NAMESPACE_REPLACE_REGEX = /^(xlink|xmlns|xml)(:|[A-Z])/;
463460
const SELF_CLOSING = new Set([
464461
'area',
465462
'base',

test/render.test.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ describe('render', () => {
333333
);
334334

335335
expect(rendered).to.equal(
336-
`<svg><image xlink:href="#"></image><foreignObject><div xlinkHref="#"></div></foreignObject><g><image xlink:href="#"></image></g></svg>`
336+
`<svg><image xlink:href="#"></image><foreignObject><div xlink:href="#"></div></foreignObject><g><image xlink:href="#"></image></g></svg>`
337337
);
338338
});
339339
});
@@ -1855,6 +1855,21 @@ describe('render', () => {
18551855
}
18561856
});
18571857

1858+
it('should replace namespaces', () => {
1859+
let rendered = render(
1860+
<svg
1861+
xmlns="http://www.w3.org/2000/svg"
1862+
xmlnsXlink="http://www.w3.org/1999/xlink"
1863+
>
1864+
<script xlinkHref="cool-script.js" />
1865+
</svg>
1866+
);
1867+
1868+
expect(rendered).to.equal(
1869+
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><script xlink:href="cool-script.js"></script></svg>'
1870+
);
1871+
});
1872+
18581873
it('should have correct HTML casing', () => {
18591874
let htmlAttributes = {
18601875
accept: 'accept',

0 commit comments

Comments
 (0)