11import  *  as  createHash  from  "murmurhash-js/murmurhash3_gc" ; 
22import  isUnitlessNumber  from  "../utils/react/isUnitlessNumber" ; 
33import  {  Theme  }  from  "./getTheme" ; 
4- import  {  CSSProperties  }  from  "react" ; 
54
65export  const  replace2Dashes  =  ( key : string )  =>  key . replace ( / [ A - Z ] / g,  $1  =>  `-${ $1 . toLowerCase ( ) }  ` ) ; 
76export  const  getStyleValue  =  ( key : string ,  value : string )  =>  ( ( typeof  value  ===  "number"  &&  ! isUnitlessNumber [ key ] )  ? `${ value }  px`  : value ) ; 
@@ -21,6 +20,7 @@ export interface StyleClasses {
2120} 
2221
2322export  interface  Sheet  { 
23+   rules ?: Map < string ,  boolean > ; 
2424  CSSText ?: string ; 
2525  className ?: string ; 
2626  classNameWithHash ?: string ; 
@@ -39,45 +39,56 @@ export interface StyleManagerConfig {
3939
4040export  class  StyleManager  { 
4141  prefixClassName : string ; 
42-   theme : Theme ; 
4342  sheets : { 
44-     [ key : string ] : Sheet 
43+     [ key : string ] : Sheet ; 
4544  }  =  { } ; 
46-   CSSText : string  =  "" ; 
45+   resultCSSText : string  =  "" ; 
4746  addedCSSText : { 
48-     [ key : string ] : boolean ; 
47+     [ key : string ] : { 
48+       CSSText ?: string ; 
49+       rules ?: Map < string ,  boolean > ; 
50+     } ; 
4951  }  =  { } ; 
52+   allRules : Map < string ,  boolean >  =  new  Map ( ) ; 
5053  onAddCSSText ( CSSText ?: string )  { } 
54+   onAddRules ( rules ?: Map < string ,  boolean > )  { } 
5155  onRemoveCSSText ( CSSText ?: string )  { } 
5256
5357  constructor ( config ?: StyleManagerConfig )  { 
5458    const  {  prefixClassName }  =  config  ||  { } ; 
5559    this . prefixClassName  =  prefixClassName  ? `${ prefixClassName }  -`  : "" ; 
5660  } 
5761
62+   setRules2allRules ( rules : Map < string ,  boolean > ,  rule : string )  { 
63+     if  ( this . allRules . get ( rule ) )  { 
64+       rules . set ( rule ,  true ) ; 
65+     }  else  { 
66+       rules . set ( rule ,  false ) ; 
67+       this . allRules . set ( rule ,  false ) 
68+     } 
69+   } 
70+ 
5871  cleanAllStyles ( )  { 
5972    this . cleanSheets ( ) ; 
6073    this . cleanCSSText ( ) ; 
6174  } 
6275
6376  cleanSheets  =  ( ) : void   =>  { 
64-     this . theme  =  null ; 
6577    this . sheets  =  { } ; 
6678  } 
6779
6880  cleanCSSText ( )  { 
69-     this . theme  =  null ; 
7081    this . addedCSSText  =  { } ; 
71-     this . CSSText  =  "" ; 
82+     this . resultCSSText  =  "" ; 
7283  } 
7384
7485  style2CSSText  =  ( style : React . CSSProperties ) : string  =>  style  ? Object . keys ( style ) . map ( key  =>  ( 
75-     `   ${ replace2Dashes ( key ) }  : ${ getStyleValue ( key ,  style [ key ] ) }  ;` 
76-   ) ) . join ( "\n " )  : void  0 
86+     `${ replace2Dashes ( key ) }  : ${ getStyleValue ( key ,  style [ key ] ) }  ;` 
87+   ) ) . join ( "  " )  : void  0 
7788
78-   sheetsToString  =  ( )  =>  `\n ${ Object . keys ( this . sheets ) . map ( id  =>  this . sheets [ id ] . CSSText ) . join ( "" ) }  ` ; 
89+   sheetsToString  =  ( )  =>  `${ Object . keys ( this . sheets ) . map ( id  =>  this . sheets [ id ] . CSSText ) . join ( "" ) }  ` ; 
7990
80-   getAllCSSText  =  ( )  =>  `${ this . sheetsToString ( ) }  \n${ this . CSSText }  ` ; 
91+   getAllCSSText  =  ( )  =>  `${ this . sheetsToString ( ) }  \n${ this . resultCSSText }  ` ; 
8192
8293  addStyle  =  ( style : CustomCSSProperties ,  className  =  "" ) : Sheet  =>  { 
8394    const  id  =  createHash ( JSON . stringify ( style ) ) ; 
@@ -88,27 +99,33 @@ export class StyleManager {
8899
89100    const  classNameWithHash  =  `${ this . prefixClassName } ${ className }  -${ id }  ` ; 
90101    let  CSSText  =  "" ; 
91-     let  contentCSSText  =  "" ; 
92-     let  extendsCSSText  =  "" ; 
102+     let  currStyleText  =  "" ; 
103+     let  extendsRules  =  "" ; 
104+     const  rules  =  new  Map < string ,  boolean > ( ) ; 
93105
94106    for  ( const  styleKey  in  style )  { 
95107      if  ( extendsStyleKeys [ styleKey ] )  { 
96108        const  extendsStyle  =  style [ styleKey ] ; 
97109        if  ( extendsStyle )  { 
98-           extendsCSSText  +=  `.${ classNameWithHash } ${ styleKey . slice ( 1 ) }   {\n${ this . style2CSSText ( extendsStyle ) }  \n}\n` ; 
110+           const  newRules  =  `.${ classNameWithHash } ${ styleKey . slice ( 1 ) }   { ${ this . style2CSSText ( extendsStyle ) }   }` ; 
111+           this . setRules2allRules ( rules ,  newRules ) ; 
112+           extendsRules  +=  newRules ; 
99113        } 
100114      }  else  { 
101115        if  ( style [ styleKey ]  !==  void  0 )  { 
102-           contentCSSText  +=  `   ${ replace2Dashes ( styleKey ) }  : ${ getStyleValue ( styleKey ,  style [ styleKey ] ) }  ;\n ` ; 
116+           currStyleText  +=  `${ replace2Dashes ( styleKey ) }  : ${ getStyleValue ( styleKey ,  style [ styleKey ] ) }  ;  ` ; 
103117        } 
104118      } 
105119    } 
106120
107-     CSSText  +=  `.${ classNameWithHash }   {\n${ contentCSSText }  \n}\n` ; 
108-     CSSText  +=  extendsCSSText ; 
121+     const  currRules  =  `.${ classNameWithHash }   { ${ currStyleText }  }` ; 
122+     this . setRules2allRules ( rules ,  currRules ) ; 
123+     CSSText  +=  currRules ; 
124+     CSSText  +=  extendsRules ; 
109125
110-     this . sheets [ id ]  =  {  CSSText,  classNameWithHash,  id,  className } ; 
111-     this . onAddCSSText ( CSSText ) ; 
126+     this . sheets [ id ]  =  {  CSSText,  classNameWithHash,  id,  className,  rules } ; 
127+     this . onAddCSSText ( currRules  +  extendsRules ) ; 
128+     this . onAddRules ( rules ) ; 
112129
113130    return  this . sheets [ id ] ; 
114131  } 
@@ -117,26 +134,41 @@ export class StyleManager {
117134    const  hash  =  createHash ( CSSText ) ; 
118135    const  shouldUpdate  =  ! this . addedCSSText [ hash ] ; 
119136    if  ( shouldUpdate )  { 
120-       this . addedCSSText [ hash ]  =  true ; 
121-       this . CSSText  +=  CSSText ; 
137+       this . resultCSSText  +=  CSSText ; 
138+       const  textSize  =  CSSText . length ; 
139+       let  currRule  =  "" ; 
140+       let  leftBraces  =  0 ; 
141+       const  rules  =  new  Map < string ,  boolean > ( ) ; 
142+       for  ( let  i  =  0 ;  i  <  textSize ;  i  ++ )  { 
143+         const  char  =  CSSText [ i ] ; 
144+         currRule  +=  char ; 
145+         if  ( char  ===  "{" )  { 
146+           leftBraces  +=  1 ; 
147+         } 
148+         if  ( char  ===  "}" )  { 
149+           leftBraces  -=  1 ; 
150+           if  ( leftBraces  ===  0 )  { 
151+             this . setRules2allRules ( rules ,  currRule ) ; 
152+             currRule  =  "" ; 
153+           } 
154+         } 
155+       } 
156+       this . addedCSSText [ hash ]  =  {  CSSText,  rules } ; 
122157      this . onAddCSSText ( CSSText ) ; 
158+       this . onAddRules ( rules ) ; 
123159    } 
124160  } 
125161
126162  removeCSSText  =  ( CSSText : string )  =>  { 
127163    const  hash  =  createHash ( CSSText ) ; 
128-     this . addedCSSText [ hash ]   =   false ; 
129-     this . CSSText  =  this . CSSText . replace ( CSSText ,  "" ) ; 
164+     delete   this . addedCSSText [ hash ] ; 
165+     this . resultCSSText  =  this . resultCSSText . replace ( CSSText ,  "" ) ; 
130166    this . onRemoveCSSText ( CSSText ) ; 
131167  } 
132168
133-   setStyleToManager ( config ?: { 
134-     style ?: CustomCSSProperties ; 
135-     className ?: string ; 
136-   } ,  callback ?: ( theme ?: Theme )  =>  StyleClasses ) : StyleClasses  { 
169+   setStyleToManager ( config ?: {  style ?: CustomCSSProperties ;  className ?: string ;  } ) : StyleClasses  { 
137170    let  newStyles : StyleClasses  =  { } ; 
138171    let  {  style,  className }  =  config  ||  { }  as  StyleClasses ; 
139-     if  ( callback )  style  =  callback ( this . theme )  as  CustomCSSProperties ; 
140172
141173    const  {  dynamicStyle,  ...styleProperties  }  =  style ; 
142174    className  =  className  ||  "" ; 
@@ -149,18 +181,14 @@ export class StyleManager {
149181    return  newStyles ; 
150182  } 
151183
152-   setStylesToManager ( config ?: { 
153-     styles : {  [ key : string ] : StyleClasses  |  CustomCSSProperties  } ; 
154-     className ?: string ; 
155-   } ,  callback ?: ( theme ?: Theme )  =>  {  [ key : string ] : StyleClasses  } ) : {  [ key : string ] : StyleClasses  }  { 
184+   setStylesToManager ( config ?: {  styles : {  [ key : string ] : StyleClasses  |  CustomCSSProperties  } ;  className ?: string ;  } ) : {  [ key : string ] : StyleClasses  }  { 
156185    const  newStyles : { 
157186      [ key : string ] : { 
158187        className ?: string ; 
159188        style ?: React . CSSProperties ; 
160189      } 
161190    }  =  { } ; 
162191    let  {  className,  styles }  =  config ; 
163-     if  ( callback )  styles  =  callback ( this . theme ) ; 
164192    className  =  className  ||  "" ; 
165193    const  keys  =  Object . keys ( styles ) ; 
166194
@@ -190,6 +218,47 @@ export class StyleManager {
190218
191219    return  newStyles ; 
192220  } 
221+ 
222+   insertRule2el ( styleEl : HTMLStyleElement ,  rule : string ,  index ?: number )  { 
223+     if  ( rule  &&  styleEl  &&  ! this . allRules . get ( rule ) )  { 
224+       const  {  sheet }  =  styleEl ; 
225+       const  rulesSize  =  sheet [ "rules" ] . size ; 
226+ 
227+       try  { 
228+         if  ( "insertRule"  in  sheet )  { 
229+           ( sheet  as  any ) [ "insertRule" ] ( rule ,  index  ===  void  0  ? rulesSize  : index ) ; 
230+         }  else  if  ( "appendRule"  in  sheet )  { 
231+           ( sheet  as  any ) [ "appendRule" ] ( rule ) ; 
232+         }  else  { 
233+           styleEl . textContent  +=  rule ; 
234+         } 
235+       }  catch  ( error )  { 
236+         console . error ( error ) ; 
237+       } 
238+     } 
239+   } 
240+ 
241+   inserAllRule2el ( styleEl : HTMLStyleElement )  { 
242+     this . allRules . forEach ( ( inserted ,  rule )  =>  { 
243+       if  ( ! inserted )  { 
244+         this . insertRule2el ( styleEl ,  rule ) ; 
245+         this . allRules . set ( rule ,  true ) ; 
246+       } 
247+     } ) ; 
248+   } 
249+ 
250+   cleanRules ( styleEl : HTMLStyleElement )  { 
251+     if  ( styleEl )  { 
252+       const  {  sheet }  =  styleEl ; 
253+       const  rules  =  sheet [ "rules" ]  as  any ; 
254+       if  ( rules  &&  rules . length  >  0 )  { 
255+         for  ( const  rule  of  rules )  { 
256+           ( sheet  as  any ) [ "deleteRule" ] ( rule ) ; 
257+         } 
258+       } 
259+       this . cleanAllStyles ( ) ; 
260+     } 
261+   } 
193262} 
194263
195264export  default  StyleManager ; 
0 commit comments