11import  *  as  ReactDOM  from  "react-dom" ; 
22
33import  domElementToReact  from  "./dom-element-to-react" ; 
4+ import  ILoadedOptions  from  "./ILoadedOptions" ; 
45import  IOptions  from  "./IOptions" ; 
56import  IRehydrator  from  "./IRehydrator" ; 
67
78const  rehydratableToReactElement  =  async  ( 
89  el : Element , 
910  rehydrators : IRehydrator , 
10-   options : IOptions 
11+   options : ILoadedOptions 
1112) : Promise < React . ReactElement < any > >  =>  { 
12-   const  rehydratorName  =  el . getAttribute ( "data-rehydratable" ) ; 
13+   const  rehydratorSelector  =  Object . keys ( options . allSelectors ) . find ( selector  => 
14+     el . matches ( selector ) 
15+   ) ; 
16+ 
17+   if  ( ! rehydratorSelector )  { 
18+     throw  new  Error ( "No rehydrator selector matched the element." ) ; 
19+   } 
20+ 
21+   const  rehydratorName  =  options . allSelectors [ rehydratorSelector ] ; 
1322
1423  if  ( ! rehydratorName )  { 
1524    throw  new  Error ( "Rehydrator name is missing from element." ) ; 
@@ -33,13 +42,13 @@ const rehydratableToReactElement = async (
3342
3443const  createCustomHandler  =  ( 
3544  rehydrators : IRehydrator , 
36-   options : IOptions 
45+   options : ILoadedOptions 
3746)  =>  async  ( node : Node )  =>  { 
3847  // This function will run on _every_ node that domElementToReact encounters. 
3948  // Make sure to keep the conditional highly performant. 
4049  if  ( 
4150    node . nodeType  ===  Node . ELEMENT_NODE  && 
42-     ( node  as  Element ) . hasAttribute ( "data-rehydratable" ) 
51+     ( node  as  Element ) . matches ( options . compoundSelector ) 
4352  )  { 
4453    return  rehydratableToReactElement ( node  as  Element ,  rehydrators ,  options ) ; 
4554  } 
@@ -63,7 +72,7 @@ const createReactRoot = (el: Node) => {
6372const  rehydrateChildren  =  async  ( 
6473  el : Node , 
6574  rehydrators : IRehydrator , 
66-   options : IOptions 
75+   options : ILoadedOptions 
6776)  =>  { 
6877  const  container  =  createReactRoot ( el ) ; 
6978
@@ -93,30 +102,55 @@ const render = ({
93102  ReactDOM . render ( rehydrated  as  React . ReactElement < any > ,  root ) ; 
94103} ; 
95104
96- const  createQuerySelector  =  ( rehydratableIds : string [ ] )  => 
97-   rehydratableIds . reduce ( 
98-     ( acc : string ,  rehydratableId : string )  => 
99-       `${ acc  ? `${ acc }   : "" } ${ rehydratableId }  , 
105+ const  defaultGetQuerySelector  =  ( key : string )  => 
106+   `[data-rehydratable*="${ key }  ; 
107+ 
108+ const  createQuerySelectors  =  ( 
109+   rehydratableIds : string [ ] , 
110+   getQuerySelector : ( ( key : string )  =>  string )  =  defaultGetQuerySelector 
111+ )  =>  { 
112+   const  allSelectors : {  [ key : string ] : string  }  =  rehydratableIds . reduce ( 
113+     ( acc ,  key )  =>  ( {  ...acc ,  [ getQuerySelector ( key ) ] : key  } ) , 
114+     { } 
115+   ) ; 
116+ 
117+   const  compoundSelector  =  Object . keys ( allSelectors ) . reduce ( 
118+     ( acc : string ,  selector : string )  =>  `${ acc  ? `${ acc }   : "" } ${ selector }  , 
100119    "" 
101120  ) ; 
102121
122+   return  { 
123+     allSelectors, 
124+     compoundSelector, 
125+   } ; 
126+ } ; 
127+ 
103128const  rehydrate  =  async  ( 
104129  container : Element , 
105130  rehydrators : IRehydrator , 
106131  options : IOptions 
107132)  =>  { 
108-   const  selector  =  createQuerySelector ( Object . keys ( rehydrators ) ) ; 
109- 
110-   const  roots  =  Array . from ( 
111-     // TODO: allow setting a container identifier so multiple rehydration instances can exist 
112-     container . querySelectorAll ( selector ) 
113-   ) . reduce ( ( acc : Element [ ] ,  root : Element )  =>  { 
114-     // filter roots that are contained within other roots 
115-     if  ( ! acc . some ( r  =>  r . contains ( root ) ) )  { 
116-       acc . push ( root ) ; 
117-     } 
118-     return  acc ; 
119-   } ,  [ ] ) ; 
133+   const  {  allSelectors,  compoundSelector }  =  createQuerySelectors ( 
134+     Object . keys ( rehydrators ) , 
135+     options . getQuerySelector 
136+   ) ; 
137+ 
138+   const  loadedOptions : ILoadedOptions  =  { 
139+     allSelectors, 
140+     compoundSelector, 
141+     extra : options . extra , 
142+   } ; 
143+ 
144+   const  roots  =  Array . from ( container . querySelectorAll ( compoundSelector ) ) . reduce ( 
145+     ( acc : Element [ ] ,  root : Element )  =>  { 
146+       // filter roots that are contained within other roots 
147+       if  ( ! acc . some ( r  =>  r . contains ( root ) ) )  { 
148+         acc . push ( root ) ; 
149+       } 
150+       return  acc ; 
151+     } , 
152+     [ ] 
153+   ) ; 
120154
121155  // TODO: solve race condition when a second rehydrate runs 
122156
@@ -130,7 +164,7 @@ const rehydrate = async (
130164          const  { 
131165            container : rootContainer , 
132166            rehydrated, 
133-           }  =  await  rehydrateChildren ( root ,  rehydrators ,  options ) ; 
167+           }  =  await  rehydrateChildren ( root ,  rehydrators ,  loadedOptions ) ; 
134168
135169          return  {  root : rootContainer ,  rehydrated } ; 
136170        }  catch  ( e )  { 
0 commit comments