@@ -10,6 +10,7 @@ import {
10
10
create ,
11
11
hasOwnProperty ,
12
12
htmlPropertyToAttribute ,
13
+ isFunction ,
13
14
isUndefined ,
14
15
KEY__SHADOW_TOKEN ,
15
16
setPrototypeOf ,
@@ -29,6 +30,10 @@ if (process.env.NODE_ENV === 'development') {
29
30
}
30
31
31
32
const globalStylesheetsParentElement : Element = document . head || document . body || document ;
33
+ const supportsConstructableStyleSheets = isFunction ( ( CSSStyleSheet . prototype as any ) . replaceSync ) ;
34
+ const styleElements : { [ content : string ] : HTMLStyleElement } = create ( null ) ;
35
+ const styleSheets : { [ content : string ] : CSSStyleSheet } = create ( null ) ;
36
+ const nodesToStyleSheets = new WeakMap < Node , { [ content : string ] : true } > ( ) ;
32
37
33
38
let getCustomElement , defineCustomElement , HTMLElementConstructor ;
34
39
@@ -54,6 +59,46 @@ function isCustomElementRegistryAvailable() {
54
59
}
55
60
}
56
61
62
+ function insertConstructableStyleSheet ( content : string , target : Node ) {
63
+ // It's important for CSSStyleSheets to be unique based on their content, so that
64
+ // `shadowRoot.adoptedStyleSheets.includes(sheet)` works.
65
+ let styleSheet = styleSheets [ content ] ;
66
+ if ( isUndefined ( styleSheet ) ) {
67
+ styleSheet = new CSSStyleSheet ( ) ;
68
+ ( styleSheet as any ) . replaceSync ( content ) ;
69
+ styleSheets [ content ] = styleSheet ;
70
+ }
71
+ if ( ! ( target as any ) . adoptedStyleSheets . includes ( styleSheet ) ) {
72
+ ( target as any ) . adoptedStyleSheets = [ ...( target as any ) . adoptedStyleSheets , styleSheet ] ;
73
+ }
74
+ }
75
+
76
+ function insertStyleElement ( content : string , target : Node ) {
77
+ // Avoid inserting duplicate `<style>`s
78
+ let sheets = nodesToStyleSheets . get ( target ) ;
79
+ if ( isUndefined ( sheets ) ) {
80
+ sheets = create ( null ) ;
81
+ nodesToStyleSheets . set ( target , sheets ! ) ;
82
+ }
83
+ if ( sheets ! [ content ] ) {
84
+ return ;
85
+ }
86
+ sheets ! [ content ] = true ;
87
+
88
+ // This `<style>` may be repeated multiple times in the DOM, so cache it. It's a bit
89
+ // faster to call `cloneNode()` on an existing node than to recreate it every time.
90
+ let elm = styleElements [ content ] ;
91
+ if ( isUndefined ( elm ) ) {
92
+ elm = document . createElement ( 'style' ) ;
93
+ elm . type = 'text/css' ;
94
+ elm . textContent = content ;
95
+ styleElements [ content ] = elm ;
96
+ } else {
97
+ elm = elm . cloneNode ( true ) as HTMLStyleElement ;
98
+ }
99
+ target . appendChild ( elm ) ;
100
+ }
101
+
57
102
if ( isCustomElementRegistryAvailable ( ) ) {
58
103
getCustomElement = customElements . get . bind ( customElements ) ;
59
104
defineCustomElement = customElements . define . bind ( customElements ) ;
@@ -244,6 +289,15 @@ export const renderer: Renderer<Node, Element> = {
244
289
globalStylesheetsParentElement . appendChild ( elm ) ;
245
290
} ,
246
291
292
+ insertStylesheet ( content : string , target : Node ) : void {
293
+ if ( supportsConstructableStyleSheets ) {
294
+ insertConstructableStyleSheet ( content , target ) ;
295
+ } else {
296
+ // Fall back to <style> element
297
+ insertStyleElement ( content , target ) ;
298
+ }
299
+ } ,
300
+
247
301
assertInstanceOfHTMLElement ( elm : any , msg : string ) {
248
302
assert . invariant ( elm instanceof HTMLElement , msg ) ;
249
303
} ,
0 commit comments