Skip to content

Commit 999cdfd

Browse files
committed
fix(core): lazy-register context providers
if consumers upgrade first, this allows them to register on providers after-the-fact
1 parent a6253d3 commit 999cdfd

File tree

3 files changed

+43
-19
lines changed

3 files changed

+43
-19
lines changed

.changeset/chatty-pears-press.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@patternfly/pfe-core": patch
3+
---
4+
5+
Register context providers even if they upgrade after the consumers

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ core/pfe-core/demo/*
127127
/docs/demo/**/*.d.ts
128128
/docs/demo/**/*.js.map
129129
/docs/demo/demo.js.LEGAL.txt
130+
/docs/demo/components.ts
130131
!/docs/demo/demo.css
131-
!/docs/demo/components.ts
132132
!/docs/core/styles/demo.njk
133133

134134

core/pfe-core/controllers/color-context-controller.ts

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { StyleController } from './style-controller.js';
1010
import CONTEXT_BASE_STYLES from './color-context-controller.scss';
1111

1212
export 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

Comments
 (0)