@@ -10,6 +10,8 @@ import { StyleController } from './style-controller.js';
1010import CONTEXT_BASE_STYLES from './color-context-controller.scss' ;
1111
1212export class ColorContextController implements ReactiveController {
13+ private static contextEvents = new Set < ContextEvent < UnknownContext > > ( ) ;
14+
1315 private callbacks = new Set < ColorContextController [ 'update' ] > ( ) ;
1416
1517 private context : Context < ContextTheme | null > ;
@@ -35,9 +37,19 @@ export class ColorContextController implements ReactiveController {
3537 */
3638 hostConnected ( ) {
3739 // register as a context consumer on the nearest context-aware ancestor
38- this . host . dispatchEvent ( new ContextEvent ( this . context , this . contextCallback , true ) ) ;
40+ const event = new ContextEvent ( this . context , this . contextCallback , true ) ;
41+ this . host . dispatchEvent ( event ) ;
42+
43+ ColorContextController . contextEvents . add ( event ) ;
44+
3945 // become a context provider
4046 this . host . addEventListener ( 'context-request' , this . onChildContextEvent ) ;
47+
48+ // re-fire all context events, in case this host upgraded after the previous one
49+ for ( const fired of ColorContextController . contextEvents ) {
50+ fired . target ?. dispatchEvent ( fired ) ;
51+ }
52+
4153 // 💃 🕺
4254 this . update ( ) ;
4355 }
@@ -63,7 +75,10 @@ export class ColorContextController implements ReactiveController {
6375 private isColorContextEvent (
6476 event : ContextEvent < UnknownContext >
6577 ) : event is ContextEvent < Context < ContextTheme | null > > {
66- return event . context . name === `${ this . prefix } -color-context` ;
78+ return (
79+ event . target !== this . host &&
80+ event . context . name === `${ this . prefix } -color-context`
81+ ) ;
6782 }
6883
6984 /** Return the current CSS `--context` value, or null */
@@ -103,22 +118,26 @@ export class ColorContextController implements ReactiveController {
103118
104119 /** Sets the `on` attribute on the host and any children that requested multiple updates */
105120 @bound public update ( fallback ?: ContextTheme | null ) {
106- // NB: We query the existing CSSStyleDeclaration on _every_. _single_. _update_.
107- const incoming = this . contextVariable || fallback ;
108- const current = this . host . getAttribute ( 'on' ) ;
109- if ( incoming !== current ) {
110- const next = incoming ;
111- this . logger . log ( `Resetting context from ${ current } to ${ next } ` ) ;
112-
113- if ( next != null ) {
114- this . host . setAttribute ( 'on' , next ) ;
115- } else {
116- this . host . removeAttribute ( 'on' ) ;
117- }
118-
119- for ( const cb of this . callbacks ) {
120- cb ( incoming ) ;
121+ // ordinarily we'd prefer async/await for this,
122+ // but in this case, we use `.then` to maintain the synchronous interface of ContextCallback
123+ this . host . updateComplete . then ( ( ) => {
124+ // NB: We query the existing CSSStyleDeclaration on _every_. _single_. _update_.
125+ const incoming = this . contextVariable || fallback ;
126+ const current = this . host . getAttribute ( 'on' ) ;
127+ if ( incoming !== current ) {
128+ const next = incoming ;
129+ this . logger . log ( `Resetting context from ${ current } to ${ next } ` ) ;
130+
131+ if ( next != null ) {
132+ this . host . setAttribute ( 'on' , next ) ;
133+ } else {
134+ this . host . removeAttribute ( 'on' ) ;
135+ }
136+
137+ for ( const cb of this . callbacks ) {
138+ cb ( incoming ) ;
139+ }
121140 }
122- }
141+ } ) ;
123142 }
124143}
0 commit comments