1
1
import {
2
2
type Component ,
3
+ type ComponentCustomElementInterface ,
3
4
type ComponentInjectOptions ,
4
5
type ComponentInternalInstance ,
5
6
type ComponentObjectPropsOptions ,
@@ -189,7 +190,10 @@ const BaseClass = (
189
190
190
191
type InnerComponentDef = ConcreteComponent & CustomElementOptions
191
192
192
- export class VueElement extends BaseClass {
193
+ export class VueElement
194
+ extends BaseClass
195
+ implements ComponentCustomElementInterface
196
+ {
193
197
/**
194
198
* @internal
195
199
*/
@@ -198,7 +202,15 @@ export class VueElement extends BaseClass {
198
202
private _connected = false
199
203
private _resolved = false
200
204
private _numberProps : Record < string , true > | null = null
205
+ private _styleChildren = new WeakSet ( )
206
+ /**
207
+ * dev only
208
+ */
201
209
private _styles ?: HTMLStyleElement [ ]
210
+ /**
211
+ * dev only
212
+ */
213
+ private _childStyles ?: Map < string , HTMLStyleElement [ ] >
202
214
private _ob ?: MutationObserver | null = null
203
215
/**
204
216
* @internal
@@ -312,13 +324,14 @@ export class VueElement extends BaseClass {
312
324
}
313
325
314
326
// apply CSS
315
- if ( __DEV__ && styles && def . shadowRoot === false ) {
327
+ if ( this . shadowRoot ) {
328
+ this . _applyStyles ( styles )
329
+ } else if ( __DEV__ && styles ) {
316
330
warn (
317
331
'Custom element style injection is not supported when using ' +
318
332
'shadowRoot: false' ,
319
333
)
320
334
}
321
- this . _applyStyles ( styles )
322
335
323
336
// initial render
324
337
this . _update ( )
@@ -329,7 +342,7 @@ export class VueElement extends BaseClass {
329
342
330
343
const asyncDef = ( this . _def as ComponentOptions ) . __asyncLoader
331
344
if ( asyncDef ) {
332
- asyncDef ( ) . then ( def => resolve ( def , true ) )
345
+ asyncDef ( ) . then ( def => resolve ( ( this . _def = def ) , true ) )
333
346
} else {
334
347
resolve ( this . _def )
335
348
}
@@ -486,19 +499,36 @@ export class VueElement extends BaseClass {
486
499
return vnode
487
500
}
488
501
489
- private _applyStyles ( styles : string [ ] | undefined ) {
490
- const root = this . shadowRoot
491
- if ( ! root ) return
492
- if ( styles ) {
493
- styles . forEach ( css => {
494
- const s = document . createElement ( 'style' )
495
- s . textContent = css
496
- root . appendChild ( s )
497
- // record for HMR
498
- if ( __DEV__ ) {
502
+ private _applyStyles (
503
+ styles : string [ ] | undefined ,
504
+ owner ?: ConcreteComponent ,
505
+ ) {
506
+ if ( ! styles ) return
507
+ if ( owner ) {
508
+ if ( owner === this . _def || this . _styleChildren . has ( owner ) ) {
509
+ return
510
+ }
511
+ this . _styleChildren . add ( owner )
512
+ }
513
+ for ( let i = styles . length - 1 ; i >= 0 ; i -- ) {
514
+ const s = document . createElement ( 'style' )
515
+ s . textContent = styles [ i ]
516
+ this . shadowRoot ! . prepend ( s )
517
+ // record for HMR
518
+ if ( __DEV__ ) {
519
+ if ( owner ) {
520
+ if ( owner . __hmrId ) {
521
+ if ( ! this . _childStyles ) this . _childStyles = new Map ( )
522
+ let entry = this . _childStyles . get ( owner . __hmrId )
523
+ if ( ! entry ) {
524
+ this . _childStyles . set ( owner . __hmrId , ( entry = [ ] ) )
525
+ }
526
+ entry . push ( s )
527
+ }
528
+ } else {
499
529
; ( this . _styles || ( this . _styles = [ ] ) ) . push ( s )
500
530
}
501
- } )
531
+ }
502
532
}
503
533
}
504
534
@@ -547,6 +577,24 @@ export class VueElement extends BaseClass {
547
577
parent . removeChild ( o )
548
578
}
549
579
}
580
+
581
+ injectChildStyle ( comp : ConcreteComponent & CustomElementOptions ) {
582
+ this . _applyStyles ( comp . styles , comp )
583
+ }
584
+
585
+ removeChildStlye ( comp : ConcreteComponent ) : void {
586
+ if ( __DEV__ ) {
587
+ this . _styleChildren . delete ( comp )
588
+ if ( this . _childStyles && comp . __hmrId ) {
589
+ // clear old styles
590
+ const oldStyles = this . _childStyles . get ( comp . __hmrId )
591
+ if ( oldStyles ) {
592
+ oldStyles . forEach ( s => this . _root . removeChild ( s ) )
593
+ oldStyles . length = 0
594
+ }
595
+ }
596
+ }
597
+ }
550
598
}
551
599
552
600
/**
@@ -557,7 +605,7 @@ export function useShadowRoot(): ShadowRoot | null {
557
605
const instance = getCurrentInstance ( )
558
606
const el = instance && instance . ce
559
607
if ( el ) {
560
- return el . shadowRoot
608
+ return ( el as VueElement ) . shadowRoot
561
609
} else if ( __DEV__ ) {
562
610
if ( ! instance ) {
563
611
warn ( `useCustomElementRoot called without an active component instance.` )
0 commit comments