11import * as React from 'react' ;
22import * as ReactDOM from 'react-dom' ;
33
4- console . log ( 'React = ' , React )
5- console . log ( 'ReactDOM = ' , ReactDOM )
6-
7- // These namespaces come from react-dom, which does not export them publicly
8- // https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/shared/DOMNamespaces.js#L8-L16
9- const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml' ;
10- const MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML' ;
4+ // ReactDOM can handle several different namespaces, but they're not exported publicly
5+ // https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/shared/DOMNamespaces.js#L8-L10
116const SVG_NAMESPACE = 'http://www.w3.org/2000/svg' ;
12- export const Namespaces = {
13- html : HTML_NAMESPACE ,
14- mathml : MATH_NAMESPACE ,
15- svg : SVG_NAMESPACE ,
16- } ;
177
188type Component < P > = React . Component < P > | React . ComponentType < P > ;
199
@@ -22,7 +12,8 @@ type ComponentProps<C extends Component<any>> = C extends Component<infer P> ? P
2212type PortalNodeElement = HTMLElement | SVGElement ;
2313
2414export interface PortalNode < C extends Component < any > = Component < any > > {
25- element : PortalNodeElement ,
15+ // The dom element used for the React portal. Created on portal mount.
16+ element : PortalNodeElement | null ,
2617 // Used by the out portal to send props back to the real element
2718 // Hooked by InPortal to become a state update (and thus rerender)
2819 setPortalProps ( p : ComponentProps < C > ) : void ;
@@ -48,9 +39,7 @@ export const createPortalNode = <C extends Component<any>>(): PortalNode<C> => {
4839 let lastPlaceholder : Node | undefined ;
4940
5041 const portalNode : PortalNode = {
51- // @ts -ignore
5242 element : null ,
53- // element: document.createElement('div'),
5443 setPortalProps : ( props : ComponentProps < C > ) => {
5544 initialProps = props ;
5645 } ,
@@ -64,31 +53,14 @@ export const createPortalNode = <C extends Component<any>>(): PortalNode<C> => {
6453 }
6554 portalNode . unmount ( ) ;
6655
67- console . log ( 'portalNode.mount()' , {
68- newParent, newPlaceholder,
69- parent, lastPlaceholder,
70- portalNode,
71- } ) ;
72-
73- if ( ! portalNode . element ) {
56+ // To support SVG and other non-html elements, the portalNode's element needs to created with
57+ // the correct namespace.
58+ if ( ! portalNode . element || portalNode . element . tagName !== newParent . tagName ) {
7459 if ( newParent instanceof SVGElement ) {
7560 portalNode . element = document . createElementNS ( SVG_NAMESPACE , newParent . tagName ) ;
7661 } else {
7762 portalNode . element = document . createElement ( newParent . tagName ) ;
7863 }
79-
80- console . log ( 'CREATED portalNode.element!!!' , portalNode . element ) ;
81-
82- } else if ( newParent . tagName !== portalNode . element . tagName ) {
83- const oldElement = portalNode . element ;
84-
85- if ( newParent instanceof SVGElement ) {
86- portalNode . element = document . createElementNS ( SVG_NAMESPACE , newParent . tagName ) ;
87- } else {
88- portalNode . element = document . createElement ( newParent . tagName ) ;
89- }
90-
91- console . log ( 'REPLACED portalNode.element!!!' , oldElement , ' -> ' , portalNode . element )
9264 }
9365
9466 newParent . replaceChild (
@@ -107,18 +79,13 @@ export const createPortalNode = <C extends Component<any>>(): PortalNode<C> => {
10779 }
10880
10981 if ( parent && lastPlaceholder ) {
110- if ( portalNode . element ) {
111- parent . replaceChild (
112- lastPlaceholder ,
113- portalNode . element
114- ) ;
115-
116- parent = undefined ;
117- lastPlaceholder = undefined ;
118- } else {
119- // Panic!
120- throw new Error ( 'No element available, in portalNode.mount!' ) ;
121- }
82+ parent . replaceChild (
83+ lastPlaceholder ,
84+ portalNode . element as PortalNodeElement
85+ ) ;
86+
87+ parent = undefined ;
88+ lastPlaceholder = undefined ;
12289 }
12390 }
12491 } ;
@@ -153,20 +120,19 @@ export class InPortal extends React.PureComponent<InPortalProps, { nodeProps: {}
153120 }
154121
155122 render ( ) {
156- console . log ( 'InPortal.render()' , this ) ;
157123 const { children, node } = this . props ;
158- console . log ( 'InPortal.render()...node = ' , node ) ;
159- console . log ( 'InPortal.render()... node.element = ' , node . element ) ;
160-
161- if ( ! node . element ) return null ;
162-
163- return ReactDOM . createPortal (
164- React . Children . map ( children , ( child ) => {
165- if ( ! React . isValidElement ( child ) ) return child ;
166- return React . cloneElement ( child , this . state . nodeProps )
167- } ) ,
168- node . element
169- ) ;
124+
125+ if ( node . element ) {
126+ return ReactDOM . createPortal (
127+ React . Children . map ( children , ( child ) => {
128+ if ( ! React . isValidElement ( child ) ) return child ;
129+ return React . cloneElement ( child , this . state . nodeProps )
130+ } ) ,
131+ node . element
132+ ) ;
133+ }
134+ // Else: the portalNode has not been mounted yet
135+ return null ;
170136 }
171137}
172138
@@ -222,8 +188,6 @@ export class OutPortal<C extends Component<any>> extends React.PureComponent<Out
222188 }
223189
224190 render ( ) {
225- console . log ( 'OutPortal.render()' , this ) ;
226-
227191 // Render a placeholder to the DOM, so we can get a reference into
228192 // our location in the DOM, and swap it out for the portaled node.
229193 return < div ref = { this . placeholderNode } /> ;
0 commit comments