-
Notifications
You must be signed in to change notification settings - Fork 48.4k
[Fiber] Support SVG by adding a container stack #8417
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Changes from all commits
18a9869
b8b2638
a450a08
3bc1b07
21e7b04
a810979
62b6241
b8846ad
2c5caa0
ae91e59
063199e
00c75b2
7debd3a
e6dd706
0d41720
dd93f0c
94cd7db
2099a2a
c08a24a
1b25dfb
5ee8dcf
5f4f36d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,11 @@ var CHILDREN = 'children'; | |
var STYLE = 'style'; | ||
var HTML = '__html'; | ||
|
||
var { | ||
svg: SVG_NAMESPACE, | ||
math: MATH_NAMESPACE, | ||
} = DOMNamespaces; | ||
|
||
// Node type for document fragments (Node.DOCUMENT_FRAGMENT_NODE). | ||
var DOC_FRAGMENT_TYPE = 11; | ||
|
||
|
@@ -451,45 +456,49 @@ function updateDOMProperties( | |
} | ||
} | ||
|
||
var ReactDOMFiberComponent = { | ||
// Assumes there is no parent namespace. | ||
function getIntrinsicNamespace(type : string) : string | null { | ||
switch (type) { | ||
case 'svg': | ||
return SVG_NAMESPACE; | ||
case 'math': | ||
return MATH_NAMESPACE; | ||
default: | ||
return null; | ||
} | ||
} | ||
|
||
// TODO: Use this to keep track of changes to the host context and use this | ||
// to determine whether we switch to svg and back. | ||
// TODO: Does this need to check the current namespace? In case these tags | ||
// happen to be valid in some other namespace. | ||
isNewHostContainer(tag : string) { | ||
return tag === 'svg' || tag === 'foreignobject'; | ||
var ReactDOMFiberComponent = { | ||
getChildNamespace(parentNamespace : string | null, type : string) : string | null { | ||
if (parentNamespace == null) { | ||
// No parent namespace: potential entry point. | ||
return getIntrinsicNamespace(type); | ||
} | ||
if (parentNamespace === SVG_NAMESPACE && type === 'foreignObject') { | ||
// We're leaving SVG. | ||
return null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add an assertion that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shame on me! |
||
} | ||
// By default, pass namespace below. | ||
return parentNamespace; | ||
}, | ||
|
||
createElement( | ||
tag : string, | ||
type : string, | ||
props : Object, | ||
rootContainerElement : Element | ||
rootContainerElement : Element, | ||
parentNamespace : string | null | ||
) : Element { | ||
validateDangerousTag(tag); | ||
validateDangerousTag(type); | ||
// TODO: | ||
// tag.toLowerCase(); Do we need to apply lower case only on non-custom elements? | ||
// const tag = type.toLowerCase(); Do we need to apply lower case only on non-custom elements? | ||
|
||
// We create tags in the namespace of their parent container, except HTML | ||
// tags get no namespace. | ||
var namespaceURI = rootContainerElement.namespaceURI; | ||
if (namespaceURI == null || | ||
namespaceURI === DOMNamespaces.svg && | ||
rootContainerElement.tagName === 'foreignObject') { | ||
namespaceURI = DOMNamespaces.html; | ||
} | ||
if (namespaceURI === DOMNamespaces.html) { | ||
if (tag === 'svg') { | ||
namespaceURI = DOMNamespaces.svg; | ||
} else if (tag === 'math') { | ||
namespaceURI = DOMNamespaces.mathml; | ||
} | ||
// TODO: Make this a new root container element. | ||
} | ||
|
||
var ownerDocument = rootContainerElement.ownerDocument; | ||
var domElement : Element; | ||
if (namespaceURI === DOMNamespaces.html) { | ||
var namespaceURI = parentNamespace || getIntrinsicNamespace(type); | ||
if (namespaceURI == null) { | ||
const tag = type.toLowerCase(); | ||
if (tag === 'script') { | ||
// Create the script via .innerHTML so its "parser-inserted" flag is | ||
// set to true and it does not execute | ||
|
@@ -499,17 +508,17 @@ var ReactDOMFiberComponent = { | |
var firstChild = ((div.firstChild : any) : HTMLScriptElement); | ||
domElement = div.removeChild(firstChild); | ||
} else if (props.is) { | ||
domElement = ownerDocument.createElement(tag, props.is); | ||
domElement = ownerDocument.createElement(type, props.is); | ||
} else { | ||
// Separate else branch instead of using `props.is || undefined` above becuase of a Firefox bug. | ||
// See discussion in https://github.com/facebook/react/pull/6896 | ||
// and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240 | ||
domElement = ownerDocument.createElement(tag); | ||
domElement = ownerDocument.createElement(type); | ||
} | ||
} else { | ||
domElement = ownerDocument.createElementNS( | ||
namespaceURI, | ||
tag | ||
type | ||
); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is likely going to be an issue to do for every update. We might want to consider just banning non-lowercase uses instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can omit this change if it's better to discuss separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we already doing this in
commitUpdate()
before my PR. So I don't see why doing this during mounting is worse. (We should fix both?)