@@ -775,16 +775,69 @@ export function focusWindow(element: Node): void {
775
775
}
776
776
}
777
777
778
- export function createStyleSheet ( container : HTMLElement = document . getElementsByTagName ( 'head' ) [ 0 ] , beforeAppend ?: ( style : HTMLStyleElement ) => void ) : HTMLStyleElement {
778
+ const globalStylesheets = new Map < HTMLStyleElement /* main stylesheet */ , Set < HTMLStyleElement /* aux window clones that track the main stylesheet */ > > ( ) ;
779
+
780
+ export function createStyleSheet ( container : HTMLElement = document . head , beforeAppend ?: ( style : HTMLStyleElement ) => void ) : HTMLStyleElement {
779
781
const style = document . createElement ( 'style' ) ;
780
782
style . type = 'text/css' ;
781
783
style . media = 'screen' ;
782
784
beforeAppend ?.( style ) ;
783
785
container . appendChild ( style ) ;
786
+
787
+ // With <head> as container, the stylesheet becomes global and is tracked
788
+ // to support auxiliary windows to clone the stylesheet.
789
+ if ( container === document . head ) {
790
+ const clonedGlobalStylesheets = new Set < HTMLStyleElement > ( ) ;
791
+ globalStylesheets . set ( style , clonedGlobalStylesheets ) ;
792
+
793
+ for ( const targetWindow of getWindows ( ) ) {
794
+ if ( targetWindow === window ) {
795
+ continue ; // main window is already tracked
796
+ }
797
+
798
+ const clone = cloneGlobalStyleSheet ( style , targetWindow ) ;
799
+ clonedGlobalStylesheets . add ( clone ) ;
800
+
801
+ event . Event . once ( onDidUnregisterWindow ) ( unregisteredWindow => {
802
+ if ( unregisteredWindow === targetWindow ) {
803
+ clonedGlobalStylesheets . delete ( clone ) ;
804
+ }
805
+ } ) ;
806
+ }
807
+ }
808
+
784
809
return style ;
785
810
}
786
811
787
- export function createMetaElement ( container : HTMLElement = document . getElementsByTagName ( 'head' ) [ 0 ] ) : HTMLMetaElement {
812
+ export function isGlobalStylesheet ( node : Node ) : boolean {
813
+ return globalStylesheets . has ( node as HTMLStyleElement ) ;
814
+ }
815
+
816
+ export function cloneGlobalStylesheets ( targetWindow : Window & typeof globalThis ) : IDisposable {
817
+ const disposables = new DisposableStore ( ) ;
818
+
819
+ for ( const [ globalStylesheet , clonedGlobalStylesheets ] of globalStylesheets ) {
820
+ const clone = cloneGlobalStyleSheet ( globalStylesheet , targetWindow ) ;
821
+
822
+ clonedGlobalStylesheets . add ( clone ) ;
823
+ disposables . add ( toDisposable ( ( ) => clonedGlobalStylesheets . delete ( clone ) ) ) ;
824
+ }
825
+
826
+ return disposables ;
827
+ }
828
+
829
+ function cloneGlobalStyleSheet ( globalStylesheet : HTMLStyleElement , targetWindow : Window & typeof globalThis ) : HTMLStyleElement {
830
+ const clone = globalStylesheet . cloneNode ( true ) as HTMLStyleElement ;
831
+ targetWindow . document . head . appendChild ( clone ) ;
832
+
833
+ for ( const rule of getDynamicStyleSheetRules ( globalStylesheet ) ) {
834
+ clone . sheet ?. insertRule ( rule . cssText , clone . sheet ?. cssRules . length ) ;
835
+ }
836
+
837
+ return clone ;
838
+ }
839
+
840
+ export function createMetaElement ( container : HTMLElement = document . head ) : HTMLMetaElement {
788
841
const meta = document . createElement ( 'meta' ) ;
789
842
container . appendChild ( meta ) ;
790
843
return meta ;
@@ -798,7 +851,7 @@ function getSharedStyleSheet(): HTMLStyleElement {
798
851
return _sharedStyleSheet ;
799
852
}
800
853
801
- function getDynamicStyleSheetRules ( style : any ) {
854
+ function getDynamicStyleSheetRules ( style : HTMLStyleElement ) {
802
855
if ( style ?. sheet ?. rules ) {
803
856
// Chrome, IE
804
857
return style . sheet . rules ;
@@ -810,15 +863,20 @@ function getDynamicStyleSheetRules(style: any) {
810
863
return [ ] ;
811
864
}
812
865
813
- export function createCSSRule ( selector : string , cssText : string , style : HTMLStyleElement = getSharedStyleSheet ( ) ) : void {
866
+ export function createCSSRule ( selector : string , cssText : string , style = getSharedStyleSheet ( ) ) : void {
814
867
if ( ! style || ! cssText ) {
815
868
return ;
816
869
}
817
870
818
- ( < CSSStyleSheet > style . sheet ) . insertRule ( selector + '{' + cssText + '}' , 0 ) ;
871
+ style . sheet ?. insertRule ( `${ selector } {${ cssText } }` , 0 ) ;
872
+
873
+ // Apply rule also to all cloned global stylesheets
874
+ for ( const clonedGlobalStylesheet of globalStylesheets . get ( style ) ?? [ ] ) {
875
+ createCSSRule ( selector , cssText , clonedGlobalStylesheet ) ;
876
+ }
819
877
}
820
878
821
- export function removeCSSRulesContainingSelector ( ruleName : string , style : HTMLStyleElement = getSharedStyleSheet ( ) ) : void {
879
+ export function removeCSSRulesContainingSelector ( ruleName : string , style = getSharedStyleSheet ( ) ) : void {
822
880
if ( ! style ) {
823
881
return ;
824
882
}
@@ -827,14 +885,23 @@ export function removeCSSRulesContainingSelector(ruleName: string, style: HTMLSt
827
885
const toDelete : number [ ] = [ ] ;
828
886
for ( let i = 0 ; i < rules . length ; i ++ ) {
829
887
const rule = rules [ i ] ;
830
- if ( rule . selectorText . indexOf ( ruleName ) !== - 1 ) {
888
+ if ( isCSSStyleRule ( rule ) && rule . selectorText . indexOf ( ruleName ) !== - 1 ) {
831
889
toDelete . push ( i ) ;
832
890
}
833
891
}
834
892
835
893
for ( let i = toDelete . length - 1 ; i >= 0 ; i -- ) {
836
- ( < any > style . sheet ) . deleteRule ( toDelete [ i ] ) ;
894
+ style . sheet ? .deleteRule ( toDelete [ i ] ) ;
837
895
}
896
+
897
+ // Remove rules also from all cloned global stylesheets
898
+ for ( const clonedGlobalStylesheet of globalStylesheets . get ( style ) ?? [ ] ) {
899
+ removeCSSRulesContainingSelector ( ruleName , clonedGlobalStylesheet ) ;
900
+ }
901
+ }
902
+
903
+ function isCSSStyleRule ( rule : CSSRule ) : rule is CSSStyleRule {
904
+ return typeof ( rule as CSSStyleRule ) . selectorText === 'string' ;
838
905
}
839
906
840
907
export function isMouseEvent ( e : unknown ) : e is MouseEvent {
0 commit comments