Skip to content

Commit f81ef5e

Browse files
fix: custom states will delay if added in constructor
1 parent 05dcd61 commit f81ef5e

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

Diff for: src/CustomStateSet.ts

+21-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ import { ICustomElement } from "./types";
33
/** Save a reference to the ref for teh CustomStateSet */
44
const customStateMap = new WeakMap<CustomStateSet, ICustomElement>();
55

6+
function addState(ref: ICustomElement, stateName: string): void {
7+
ref.toggleAttribute(stateName, true);
8+
if (ref.part) {
9+
ref.part.add(stateName);
10+
}
11+
}
12+
613
export type CustomState = `--${string}`;
714

815
export class CustomStateSet extends Set<CustomState> {
@@ -25,10 +32,21 @@ export class CustomStateSet extends Set<CustomState> {
2532
}
2633
const result = super.add(state);
2734
const ref = customStateMap.get(this);
28-
ref.toggleAttribute(`state${state}`, true);
29-
if (ref.part) {
30-
ref.part.add(`state${state}`);
35+
const stateName = `state${state}`;
36+
37+
/**
38+
* Only add the state immediately if the ref is connected to the DOM;
39+
* otherwise, wait a tick because the element is likely being constructed
40+
* by document.createElement and would throw otherwise.
41+
*/
42+
if (ref.isConnected) {
43+
addState(ref, stateName);
44+
} else {
45+
setTimeout(() => {
46+
addState(ref, stateName);
47+
});
3148
}
49+
3250
return result;
3351
}
3452

Diff for: test/CustomStateSet.test.ts

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
1-
import { fixture, html, expect, fixtureCleanup } from '@open-wc/testing';
1+
import '../dist/index.js';
2+
3+
import { fixture, html, expect, fixtureCleanup, aTimeout } from '@open-wc/testing';
24
import { ICustomElement } from '../dist';
35
import { CustomStateSet } from '../src/CustomStateSet';
46

7+
class CustomElementStateInConstructor extends HTMLElement {
8+
internals = this.attachInternals();
9+
constructor() {
10+
super();
11+
12+
this.internals.states.add('--foo');
13+
}
14+
}
15+
16+
const tagName = 'custom-element-state-in-constructor'
17+
customElements.define(tagName, CustomElementStateInConstructor);
18+
519
describe('CustomStateSet polyfill', () => {
620
let el: HTMLElement;
721
let set: CustomStateSet;
@@ -56,4 +70,18 @@ describe('CustomStateSet polyfill', () => {
5670
expect(el.part.contains('state--bar')).to.be.false;
5771
}
5872
});
73+
74+
it('will use a timeout if a state is added in a constructor', async () => {
75+
let el;
76+
expect(() => {
77+
el = document.createElement(tagName);
78+
}).not.to.throw();
79+
80+
if (window.CustomStateSet.isPolyfilled) {
81+
await aTimeout(100);
82+
expect(el.matches('[state--foo]')).to.be.true;
83+
} else {
84+
expect(el.matches(`:--foo`)).to.be.true;
85+
}
86+
});
5987
});

0 commit comments

Comments
 (0)