Add SVG/MathML support for createElement mode
Ben Alpert committed
Oct 8, 2015 at 15:51 UTC
8210299437d38af8c4b20f0c714511bd124e5b8a
3 files changed
+59
-3
src/renderers/dom/shared/DOMNamespaces.js
new
+20
@@ -0,0 +1,20 @@
1
+/**
2
+ * Copyright 2013-2015, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule DOMNamespaces
10
+ */
11
+
12
+'use strict';
13
+
14
+var DOMNamespaces = {
15
+ html: 'http://www.w3.org/1999/xhtml',
16
+ mathml: 'http://www.w3.org/1998/Math/MathML',
17
+ svg: 'http://www.w3.org/2000/svg',
18
+};
19
+
20
+module.exports = DOMNamespaces;
src/renderers/dom/shared/ReactDOMComponent.js
+36
-1
@@ -16,6 +16,7 @@
16
17
var AutoFocusUtils = require('AutoFocusUtils');
18
var CSSPropertyOperations = require('CSSPropertyOperations');
19
+var DOMNamespaces = require('DOMNamespaces');
20
var DOMProperty = require('DOMProperty');
21
var DOMPropertyOperations = require('DOMPropertyOperations');
22
var EventConstants = require('EventConstants');
@@ -503,6 +504,7 @@ function getNode(inst) {
504
function ReactDOMComponent(tag) {
505
validateDangerousTag(tag);
506
this._tag = tag.toLowerCase();
507
+ this._namespaceURI = null;
508
this._renderedChildren = null;
509
this._previousStyle = null;
510
this._previousStyleCopy = null;
@@ -582,6 +584,31 @@ ReactDOMComponent.Mixin = {
584
}
585
586
assertValidProps(this, props);
587
+
588
+ // We create tags in the namespace of their parent container, except HTML
589
+ // tags get no namespace.
590
+ var namespaceURI;
591
+ var parentTag;
592
+ if (nativeParent != null) {
593
+ namespaceURI = nativeParent._namespaceURI;
594
+ parentTag = nativeParent._tag;
595
+ } else if (nativeContainerInfo != null) {
596
+ namespaceURI = nativeContainerInfo._namespaceURI;
597
+ parentTag = nativeContainerInfo._tag;
598
+ }
599
+ if (namespaceURI == null ||
600
+ namespaceURI === DOMNamespaces.svg && parentTag === 'foreignobject') {
601
+ namespaceURI = DOMNamespaces.html;
602
+ }
603
+ if (namespaceURI === DOMNamespaces.html) {
604
+ if (this._tag === 'svg') {
605
+ namespaceURI = DOMNamespaces.svg;
606
+ } else if (this._tag === 'math') {
607
+ namespaceURI = DOMNamespaces.mathml;
608
+ }
609
+ }
610
+ this._namespaceURI = namespaceURI;
611
+
612
if (__DEV__) {
613
var parentInfo;
614
if (nativeParent != null) {
@@ -601,7 +628,15 @@ ReactDOMComponent.Mixin = {
628
var mountImage;
629
if (transaction.useCreateElement) {
630
var ownerDocument = nativeContainerInfo._ownerDocument;
604
- var el = ownerDocument.createElement(this._currentElement.type);
631
+ var el;
632
+ if (namespaceURI === DOMNamespaces.html) {
633
+ el = ownerDocument.createElement(this._currentElement.type);
634
+ } else {
635
+ el = ownerDocument.createElementNS(
636
+ namespaceURI,
637
+ this._currentElement.type
638
+ );
639
+ }
640
this._nativeNode = el;
641
DOMPropertyOperations.setAttributeForID(el, this._rootNodeID);
642
// Populate node cache
src/renderers/dom/shared/ReactDOMContainerInfo.js
+3
-2
@@ -18,11 +18,12 @@ var DOC_NODE_TYPE = 9;
18
function ReactDOMContainerInfo(node) {
19
var info = {
20
_ownerDocument: node.nodeType === DOC_NODE_TYPE ? node : node.ownerDocument,
21
+ _tag: node.nodeName.toLowerCase(),
22
+ _namespaceURI: node.namespaceURI,
23
};
24
if (__DEV__) {
23
- var tag = node.nodeName.toLowerCase();
25
info._ancestorInfo =
25
- validateDOMNesting.updatedAncestorInfo(null, tag, null);
26
+ validateDOMNesting.updatedAncestorInfo(null, info._tag, null);
27
}
28
return info;
29
}