Skip to content

Commit 589e75e

Browse files
authored
refactor: allow reusing CSSPropertyObserver instance for a style root (#10383)
1 parent e3beab8 commit 589e75e

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

packages/vaadin-themable-mixin/src/css-property-observer.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,22 @@
99
*
1010
* @private
1111
*/
12-
export class CSSPropertyObserver {
12+
export class CSSPropertyObserver extends EventTarget {
1313
#root;
14-
#callback;
1514
#properties = new Set();
1615
#styleSheet;
1716
#isConnected = false;
1817

19-
constructor(root, callback) {
18+
constructor(root) {
19+
super();
2020
this.#root = root;
21-
this.#callback = callback;
2221
this.#styleSheet = new CSSStyleSheet();
2322
}
2423

2524
#handleTransitionEvent(event) {
2625
const { propertyName } = event;
2726
if (this.#properties.has(propertyName)) {
28-
this.#callback(propertyName);
27+
this.dispatchEvent(new CustomEvent('property-changed', { detail: { propertyName } }));
2928
}
3029
}
3130

@@ -78,4 +77,14 @@ export class CSSPropertyObserver {
7877
get #rootHost() {
7978
return this.#root.documentElement ?? this.#root.host;
8079
}
80+
81+
/**
82+
* Gets or creates the CSSPropertyObserver for the given root.
83+
* @param {DocumentOrShadowRoot} root
84+
* @returns {CSSPropertyObserver}
85+
*/
86+
static for(root) {
87+
root.__cssPropertyObserver ||= new CSSPropertyObserver(root);
88+
return root.__cssPropertyObserver;
89+
}
8190
}

packages/vaadin-themable-mixin/src/lumo-injector.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,13 @@ export class LumoInjector {
8282

8383
constructor(root = document) {
8484
this.#root = root;
85-
this.#cssPropertyObserver = new CSSPropertyObserver(this.#root, (propertyName) => {
86-
const tagName = propertyName.match(/^--_lumo-(.*)-inject$/u)?.[1];
87-
this.#updateStyleSheet(tagName);
88-
});
85+
this.handlePropertyChange = this.handlePropertyChange.bind(this);
86+
this.#cssPropertyObserver = CSSPropertyObserver.for(root);
87+
this.#cssPropertyObserver.addEventListener('property-changed', this.handlePropertyChange);
8988
}
9089

9190
disconnect() {
92-
this.#cssPropertyObserver.disconnect();
91+
this.#cssPropertyObserver.removeEventListener('property-changed', this.handlePropertyChange);
9392
this.#styleSheetsByTag.clear();
9493
this.#componentsByTag.values().forEach((components) => components.forEach(removeLumoStyleSheet));
9594
}
@@ -134,6 +133,14 @@ export class LumoInjector {
134133
removeLumoStyleSheet(component);
135134
}
136135

136+
handlePropertyChange(event) {
137+
const { propertyName } = event.detail;
138+
const tagName = propertyName.match(/^--_lumo-(.*)-inject$/u)?.[1];
139+
if (tagName) {
140+
this.#updateStyleSheet(tagName);
141+
}
142+
}
143+
137144
#initStyleSheet(tagName) {
138145
this.#styleSheetsByTag.set(tagName, new CSSStyleSheet());
139146
this.#updateStyleSheet(tagName);

packages/vaadin-themable-mixin/test/lumo-injection-mixin.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ describe('Lumo injection', () => {
120120
afterEach(() => {
121121
document.__lumoInjector?.disconnect();
122122
document.__lumoInjector = undefined;
123+
document.__cssPropertyObserver?.disconnect();
124+
document.__cssPropertyObserver = undefined;
123125
});
124126

125127
describe('styles added after element is connected', () => {
@@ -245,6 +247,8 @@ describe('Lumo injection', () => {
245247
afterEach(() => {
246248
host.__lumoInjector?.disconnect();
247249
host.__lumoInjector = undefined;
250+
host.__cssPropertyObserver?.disconnect();
251+
host.__cssPropertyObserver = undefined;
248252
});
249253

250254
describe('styles added after element is connected', () => {
@@ -426,6 +430,8 @@ describe('Lumo injection', () => {
426430
afterEach(() => {
427431
host.__lumoInjector?.disconnect();
428432
host.__lumoInjector = undefined;
433+
host.__cssPropertyObserver?.disconnect();
434+
host.__cssPropertyObserver = undefined;
429435
});
430436

431437
it('should inject matching styles added to parent shadow host', async () => {
@@ -465,6 +471,8 @@ describe('Lumo injection', () => {
465471
afterEach(() => {
466472
document.__lumoInjector?.disconnect();
467473
document.__lumoInjector = undefined;
474+
document.__cssPropertyObserver?.disconnect();
475+
document.__cssPropertyObserver = undefined;
468476
});
469477

470478
it('should inject matching styles for the extending component', async () => {
@@ -505,6 +513,8 @@ describe('Lumo injection', () => {
505513
style.remove();
506514
document.__lumoInjector?.disconnect();
507515
document.__lumoInjector = undefined;
516+
document.__cssPropertyObserver?.disconnect();
517+
document.__cssPropertyObserver = undefined;
508518
});
509519

510520
it('should not remove styles from injected stylesheets when calling registerStyles()', () => {

0 commit comments

Comments
 (0)