Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass parent tag to text component for SVG #3351

Closed
wants to merge 2 commits into from

Conversation

nhunzaker
Copy link
Contributor

I realize this is quite a non-trivial change to React internals, however this PR adds an additional argument to mountComponent that passes in the parent tag name. This fixes issues where <span> tags are injected into <text> svg elements, nuking SVG graphics as demonstrated here:

http://jsfiddle.net/22oow6ed/1/

After this change I updated the basic example and the result is as one would expect:

screen shot 2015-03-09 at 12 14 08 pm

Frankly, passing in an additional argument feels wrong. I am curious if there is a better way to pass the required contextual information to TextComponent. Thoughts?


Fix #1236

var tag = parentTag === 'text' ? 'tspan' : 'span';
var attrs = DOMPropertyOperations.createMarkupForID(rootID);

return `<${ tag } ${ attrs }>${ escapedText }</${ tag }>`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

template strings are ES6 feature so this will not work for some target browsers

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We compile the code down to ES3 before shipping it, so this syntax is fine.

@zpao
Copy link
Member

zpao commented Mar 12, 2015

Hmm, I'm ok with this in principal, but I'm not wild about putting DOM specific things into core like this. This definitely isn't the first thing but we're also trying to move in the direction where core is pure and reusable between web and react-native. @spicyj you've worked on both so you might have a better perspective on if this sort of change would set back that goal or if it's manageable. (also @sebmarkbage)

@nhunzaker
Copy link
Contributor Author

@zpao If this doesn't make it in, I'd lobby for a warning of some kind. It's sort of alarming and confusing when you see the text from your SVG graphic appear below the containing element!

@sophiebits
Copy link
Collaborator

We could use context for this:

diff --git a/src/browser/ui/ReactDOMComponent.js b/src/browser/ui/ReactDOMComponent.js
index 4df78e8..7f4fd9e 100644
--- a/src/browser/ui/ReactDOMComponent.js
+++ b/src/browser/ui/ReactDOMComponent.js
@@ -301,7 +301,7 @@ ReactDOMComponent.Mixin = {
         var mountImages = this.mountChildren(
           childrenToUse,
           transaction,
-          context
+          assign({}, context, {svgTextChild: this._tag === 'text'})
         );
         ret = mountImages.join('');
       }
@@ -342,7 +342,11 @@ ReactDOMComponent.Mixin = {
   updateComponent: function(transaction, prevElement, nextElement, context) {
     assertValidProps(this, this._currentElement.props);
     this._updateDOMProperties(prevElement.props, transaction);
-    this._updateDOMChildren(prevElement.props, transaction, context);
+    this._updateDOMChildren(
+      prevElement.props,
+      transaction,
+      assign({}, context, {svgTextChild: this._tag === 'text'})
+    );
   },

   /**
diff --git a/src/browser/ui/ReactDOMTextComponent.js b/src/browser/ui/ReactDOMTextComponent.js
index d561646..46f8817 100644
--- a/src/browser/ui/ReactDOMTextComponent.js
+++ b/src/browser/ui/ReactDOMTextComponent.js
@@ -75,10 +75,12 @@ assign(ReactDOMTextComponent.prototype, {
       return escapedText;
     }

+    var tag = context.svgTextChild ? 'tspan' : 'span';
+
     return (
-      '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
+      '<' + tag + ' ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
         escapedText +
-      '</span>'
+      '</' + tag + '>'
     );
   },

though we'd need to make the name not clash with user-defined context keys and change the code to be smarter about not copying. Works as a proof of concept though.

@nhunzaker
Copy link
Contributor Author

@spicyj I rather quite like that. I'm still getting grips on context, but I like it!

@nhunzaker
Copy link
Contributor Author

I went ahead with that diff to keep the ball rolling. I'll also experiment with eliminating the unnecessary copies with assign.

@nhunzaker
Copy link
Contributor Author

With the new updates in React 15.x, this PR seems no longer valid. I'm going to close it.

@nhunzaker nhunzaker closed this Mar 9, 2016
@sophiebits
Copy link
Collaborator

Yeah, I ended up solving this a different way. Thanks for sending this in though – though we didn't merge it, I appreciate the discussion and we may not have fixed this in 15.0 otherwise.

@nhunzaker
Copy link
Contributor Author

No worries! I'm glad the fix is in!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Whitespace kills SVG text
5 participants