1212
1313'use strict' ;
1414
15+ import type { Fiber } from 'ReactFiber' ;
16+
1517export type HostContext < I , C > = {
1618 getHostParentOnStack ( ) : I | null ,
1719 pushHostParent ( instance : I ) : void ,
@@ -22,20 +24,20 @@ export type HostContext<I, C> = {
2224 pushHostContainer ( instance : I | C ) : void ,
2325 popHostContainer ( ) : void ,
2426
25- resetHostStacks ( ) : void ,
27+ resetHostContext ( ) : void ,
28+ saveHostContextToPortal ( portal : Fiber ) : void ,
29+ restoreHostContextFromPortal ( portal : Fiber ) : void ,
2630} ;
2731
2832module . exports = function < I , C > ( ) : HostContext < I , C > {
2933 // Host instances currently on the stack that have not yet been committed.
30- const parentStack : Array < I | null > = [ ] ;
34+ let parentStack : Array < I | null > = [ ] ;
3135 let parentIndex = - 1 ;
3236
3337 // Container instances currently on the stack (e.g. DOM uses this for SVG).
34- const containerStack : Array < C | I | null > = [ ] ;
38+ let containerStack : Array < C | I | null > = [ ] ;
3539 let containerIndex = - 1 ;
3640
37- // TODO: this is all likely broken with portals.
38-
3941 function getHostParentOnStack ( ) : I | null {
4042 if ( parentIndex === - 1 ) {
4143 return null ;
@@ -77,11 +79,42 @@ module.exports = function<I, C>() : HostContext<I, C> {
7779 containerIndex -- ;
7880 }
7981
80- function resetHostStacks ( ) : void {
82+ function resetHostContext ( ) : void {
8183 parentIndex = - 1 ;
8284 containerIndex = - 1 ;
8385 }
8486
87+ function saveHostContextToPortal ( portal : Fiber ) {
88+ const stateNode = portal . stateNode ;
89+ // We don't throw if it already exists here because it might exist
90+ // if something inside threw, and we started from the top.
91+ // TODO: add tests for error boundaries inside portals when both are stable.
92+ stateNode . savedHostContext = {
93+ containerStack,
94+ containerIndex,
95+ parentStack,
96+ parentIndex,
97+ } ;
98+ containerStack = [ ] ;
99+ containerIndex = - 1 ;
100+ parentStack = [ ] ;
101+ parentIndex = - 1 ;
102+ pushHostContainer ( stateNode . containerInfo ) ;
103+ }
104+
105+ function restoreHostContextFromPortal ( portal : Fiber ) {
106+ const stateNode = portal . stateNode ;
107+ const savedHostContext = stateNode . savedHostContext ;
108+ stateNode . savedHostContext = null ;
109+ if ( savedHostContext == null ) {
110+ throw new Error ( 'A portal has no host context saved on it.' ) ;
111+ }
112+ containerStack = savedHostContext . containerStack ;
113+ containerIndex = savedHostContext . containerIndex ;
114+ parentStack = savedHostContext . parentStack ;
115+ parentIndex = savedHostContext . parentIndex ;
116+ }
117+
85118 return {
86119 getHostParentOnStack ,
87120 pushHostParent ,
@@ -92,6 +125,8 @@ module.exports = function<I, C>() : HostContext<I, C> {
92125 pushHostContainer ,
93126 popHostContainer ,
94127
95- resetHostStacks,
128+ resetHostContext ,
129+ saveHostContextToPortal ,
130+ restoreHostContextFromPortal ,
96131 } ;
97132} ;
0 commit comments