@joist/element 4.0.0-next.41 → 4.0.0-next.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/package.json +1 -1
  2. package/src/lib/attr-changed.test.ts +11 -11
  3. package/src/lib/attr-changed.ts +3 -3
  4. package/src/lib/attr.test.ts +52 -51
  5. package/src/lib/attr.ts +8 -8
  6. package/src/lib/element.test.ts +29 -29
  7. package/src/lib/element.ts +34 -26
  8. package/src/lib/lifecycle.test.ts +10 -10
  9. package/src/lib/lifecycle.ts +5 -2
  10. package/src/lib/listen.test.ts +27 -27
  11. package/src/lib/listen.ts +5 -5
  12. package/src/lib/metadata.ts +8 -6
  13. package/src/lib/query.test.ts +12 -12
  14. package/src/lib/query.ts +16 -6
  15. package/src/lib/tags.ts +7 -4
  16. package/src/lib/template.test.ts +35 -35
  17. package/src/lib/template.ts +27 -15
  18. package/src/lib.ts +7 -7
  19. package/target/lib/attr-changed.d.ts +2 -1
  20. package/target/lib/attr-changed.js +1 -1
  21. package/target/lib/attr-changed.js.map +1 -1
  22. package/target/lib/attr-changed.test.js +11 -11
  23. package/target/lib/attr.js +7 -7
  24. package/target/lib/attr.test.js +58 -57
  25. package/target/lib/attr.test.js.map +1 -1
  26. package/target/lib/element.d.ts +1 -1
  27. package/target/lib/element.js +24 -22
  28. package/target/lib/element.js.map +1 -1
  29. package/target/lib/element.test.js +29 -29
  30. package/target/lib/element.test.js.map +1 -1
  31. package/target/lib/lifecycle.d.ts +1 -1
  32. package/target/lib/lifecycle.js +1 -1
  33. package/target/lib/lifecycle.js.map +1 -1
  34. package/target/lib/lifecycle.test.js +10 -10
  35. package/target/lib/lifecycle.test.js.map +1 -1
  36. package/target/lib/listen.d.ts +1 -1
  37. package/target/lib/listen.js +3 -3
  38. package/target/lib/listen.js.map +1 -1
  39. package/target/lib/listen.test.js +27 -27
  40. package/target/lib/listen.test.js.map +1 -1
  41. package/target/lib/metadata.d.ts +5 -4
  42. package/target/lib/metadata.js +1 -1
  43. package/target/lib/metadata.js.map +1 -1
  44. package/target/lib/query.js +1 -1
  45. package/target/lib/query.js.map +1 -1
  46. package/target/lib/query.test.js +12 -12
  47. package/target/lib/tags.d.ts +1 -1
  48. package/target/lib/tags.js +6 -3
  49. package/target/lib/tags.js.map +1 -1
  50. package/target/lib/template.js +14 -12
  51. package/target/lib/template.js.map +1 -1
  52. package/target/lib/template.test.js +31 -31
  53. package/target/lib/template.test.js.map +1 -1
  54. package/target/lib.d.ts +7 -7
  55. package/target/lib.js +7 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joist/element",
3
- "version": "4.0.0-next.41",
3
+ "version": "4.0.0-next.44",
4
4
  "type": "module",
5
5
  "main": "./target/lib.js",
6
6
  "module": "./target/lib.js",
@@ -1,20 +1,20 @@
1
- import { assert } from 'chai';
1
+ import { assert } from "chai";
2
2
 
3
- import { attrChanged } from './attr-changed.js';
4
- import { attr } from './attr.js';
5
- import { element } from './element.js';
3
+ import { attrChanged } from "./attr-changed.js";
4
+ import { attr } from "./attr.js";
5
+ import { element } from "./element.js";
6
6
 
7
- it('should call specific attrbute callback', () => {
7
+ it("should call specific attrbute callback", () => {
8
8
  let args: string[] = [];
9
9
 
10
10
  @element({
11
- tagName: 'attr-changed-1'
11
+ tagName: "attr-changed-1",
12
12
  })
13
13
  class MyElement extends HTMLElement {
14
14
  @attr()
15
- accessor test = 'hello';
15
+ accessor test = "hello";
16
16
 
17
- @attrChanged('test')
17
+ @attrChanged("test")
18
18
  onTestChanged(oldValue: string, newValue: string) {
19
19
  args = [oldValue, newValue];
20
20
  }
@@ -24,11 +24,11 @@ it('should call specific attrbute callback', () => {
24
24
 
25
25
  document.body.append(el);
26
26
 
27
- assert.deepEqual(args, [null, 'hello']);
27
+ assert.deepEqual(args, [null, "hello"]);
28
28
 
29
- el.setAttribute('test', 'world');
29
+ el.setAttribute("test", "world");
30
30
 
31
- assert.deepEqual(args, ['hello', 'world']);
31
+ assert.deepEqual(args, ["hello", "world"]);
32
32
 
33
33
  el.remove();
34
34
  });
@@ -1,9 +1,9 @@
1
- import { metadataStore } from './metadata.js';
1
+ import { type AttrChangedCallback, metadataStore } from "./metadata.js";
2
2
 
3
3
  export function attrChanged(name: string) {
4
4
  return function attrChangedDecorator<This extends HTMLElement>(
5
- cb: Function,
6
- ctx: ClassMethodDecoratorContext<This>
5
+ cb: AttrChangedCallback,
6
+ ctx: ClassMethodDecoratorContext<This>,
7
7
  ): void {
8
8
  const meta = metadataStore.read(ctx.metadata);
9
9
  const val = meta.attrChanges.get(name) ?? new Set();
@@ -1,11 +1,11 @@
1
- import { expect } from 'chai';
1
+ import { expect } from "chai";
2
2
 
3
- import { attr } from './attr.js';
4
- import { element } from './element.js';
3
+ import { attr } from "./attr.js";
4
+ import { element } from "./element.js";
5
5
 
6
- it('should read and parse the correct values', () => {
6
+ it("should read and parse the correct values", () => {
7
7
  @element({
8
- tagName: 'attr-test-1'
8
+ tagName: "attr-test-1",
9
9
  })
10
10
  class MyElement extends HTMLElement {
11
11
  @attr()
@@ -18,29 +18,29 @@ it('should read and parse the correct values', () => {
18
18
  accessor value3 = false; // boolean
19
19
 
20
20
  @attr()
21
- accessor value4 = 'hello'; // string
21
+ accessor value4 = "hello"; // string
22
22
  }
23
23
 
24
- const container = document.createElement('div');
24
+ const container = document.createElement("div");
25
25
  container.innerHTML = /*html*/ `
26
26
  <attr-test-1 value2="2" value3 value4="world"></attr-test-1>
27
27
  `;
28
28
 
29
29
  document.body.append(container);
30
30
 
31
- const el = document.querySelector('attr-test-1') as MyElement;
31
+ const el = document.querySelector("attr-test-1") as MyElement;
32
32
 
33
33
  expect(el.value1).to.equal(100);
34
34
  expect(el.value2).to.equal(2);
35
35
  expect(el.value3).to.equal(true);
36
- expect(el.value4).to.equal('world');
36
+ expect(el.value4).to.equal("world");
37
37
 
38
38
  container.remove();
39
39
  });
40
40
 
41
- it('should not write falsy props to attributes', async () => {
41
+ it("should not write falsy props to attributes", async () => {
42
42
  @element({
43
- tagName: 'attr-test-2'
43
+ tagName: "attr-test-2",
44
44
  })
45
45
  class MyElement extends HTMLElement {
46
46
  @attr()
@@ -50,23 +50,23 @@ it('should not write falsy props to attributes', async () => {
50
50
  accessor value2 = null;
51
51
 
52
52
  @attr()
53
- accessor value3 = '';
53
+ accessor value3 = "";
54
54
  }
55
55
 
56
56
  const el = new MyElement();
57
57
 
58
- expect(el.hasAttribute('value1')).to.be.false;
59
- expect(el.hasAttribute('value2')).to.be.false;
60
- expect(el.hasAttribute('value3')).to.be.false;
58
+ expect(el.hasAttribute("value1")).to.be.false;
59
+ expect(el.hasAttribute("value2")).to.be.false;
60
+ expect(el.hasAttribute("value3")).to.be.false;
61
61
  });
62
62
 
63
- it('should update attributes when props are changed', async () => {
63
+ it("should update attributes when props are changed", async () => {
64
64
  @element({
65
- tagName: 'attr-test-3'
65
+ tagName: "attr-test-3",
66
66
  })
67
67
  class MyElement extends HTMLElement {
68
68
  @attr()
69
- accessor value1 = 'hello'; // no attribute
69
+ accessor value1 = "hello"; // no attribute
70
70
 
71
71
  @attr()
72
72
  accessor value2 = 0; // number
@@ -80,29 +80,30 @@ it('should update attributes when props are changed', async () => {
80
80
 
81
81
  const el = new MyElement();
82
82
 
83
- el.value1 = 'world';
83
+ el.value1 = "world";
84
84
  el.value2 = 100;
85
85
  el.value3 = false;
86
86
  el.value4 = true;
87
87
 
88
- expect(el.getAttribute('value1')).to.equal('world');
89
- expect(el.getAttribute('value2')).to.equal('100');
90
- expect(el.hasAttribute('value3')).to.be.false;
91
- expect(el.hasAttribute('value4')).to.be.true;
88
+ expect(el.getAttribute("value1")).to.equal("world");
89
+ expect(el.getAttribute("value2")).to.equal("100");
90
+ expect(el.hasAttribute("value3")).to.be.false;
91
+ expect(el.hasAttribute("value4")).to.be.true;
92
92
  });
93
93
 
94
- it('should normalize attribute names', async () => {
95
- const value3 = Symbol('Value from SYMBOL');
94
+ it("should normalize attribute names", async () => {
95
+ const value2 = "Value 2";
96
+ const value3 = Symbol("Value from SYMBOL");
96
97
 
97
98
  @element({
98
- tagName: 'attr-test-4'
99
+ tagName: "attr-test-4",
99
100
  })
100
101
  class MyElement extends HTMLElement {
101
102
  @attr()
102
- accessor Value1 = 'hello';
103
+ accessor Value1 = "hello";
103
104
 
104
105
  @attr()
105
- accessor ['Value 2'] = 0;
106
+ accessor [value2] = 0;
106
107
 
107
108
  @attr()
108
109
  accessor [value3] = true;
@@ -113,20 +114,20 @@ it('should normalize attribute names', async () => {
113
114
  document.body.append(el);
114
115
 
115
116
  expect([...el.attributes].map((attr) => attr.name)).to.deep.equal([
116
- 'value1',
117
- 'value-2',
118
- 'value-from-symbol'
117
+ "value1",
118
+ "value-2",
119
+ "value-from-symbol",
119
120
  ]);
120
121
 
121
122
  el.remove();
122
123
  });
123
124
 
124
- it('should throw an error for symbols with no description', async () => {
125
+ it("should throw an error for symbols with no description", async () => {
125
126
  expect(() => {
126
127
  const value = Symbol();
127
128
 
128
129
  @element({
129
- tagName: 'attr-test-4'
130
+ tagName: "attr-test-4",
130
131
  })
131
132
  class MyElement extends HTMLElement {
132
133
  @attr()
@@ -134,58 +135,58 @@ it('should throw an error for symbols with no description', async () => {
134
135
  }
135
136
 
136
137
  new MyElement();
137
- }).to.throw('Cannot handle Symbol property without description');
138
+ }).to.throw("Cannot handle Symbol property without description");
138
139
  });
139
140
 
140
- it('should not reflect property to attribute', async () => {
141
+ it("should not reflect property to attribute", async () => {
141
142
  @element({
142
- tagName: 'attr-test-5'
143
+ tagName: "attr-test-5",
143
144
  })
144
145
  class MyElement extends HTMLElement {
145
146
  @attr({ reflect: false })
146
- accessor value = 'foo';
147
+ accessor value = "foo";
147
148
  }
148
149
 
149
150
  const el = new MyElement();
150
- el.value = 'bar';
151
+ el.value = "bar";
151
152
 
152
- expect(el.value).to.equal('bar');
153
+ expect(el.value).to.equal("bar");
153
154
 
154
- expect(el.hasAttribute('value')).to.be.false;
155
+ expect(el.hasAttribute("value")).to.be.false;
155
156
  });
156
157
 
157
- it('non reflective attributes should still read new attribute values', async () => {
158
+ it("non reflective attributes should still read new attribute values", async () => {
158
159
  @element({
159
- tagName: 'attr-test-6'
160
+ tagName: "attr-test-6",
160
161
  })
161
162
  class MyElement extends HTMLElement {
162
163
  @attr({ reflect: false })
163
- accessor value = 'foo';
164
+ accessor value = "foo";
164
165
  }
165
166
 
166
167
  const el = new MyElement();
167
- el.setAttribute('value', 'bar');
168
+ el.setAttribute("value", "bar");
168
169
 
169
- expect(el.value).to.equal('bar');
170
+ expect(el.value).to.equal("bar");
170
171
  });
171
172
 
172
- it('should allow a manually defined attribute name', async () => {
173
+ it("should allow a manually defined attribute name", async () => {
173
174
  @element({
174
- tagName: 'attr-test-7'
175
+ tagName: "attr-test-7",
175
176
  })
176
177
  class MyElement extends HTMLElement {
177
178
  @attr({
178
- name: 'aria-label'
179
+ name: "aria-label",
179
180
  })
180
- accessor value = '';
181
+ accessor value = "";
181
182
  }
182
183
 
183
184
  const el = new MyElement();
184
- el.setAttribute('aria-label', 'TEST');
185
+ el.setAttribute("aria-label", "TEST");
185
186
 
186
187
  document.body.append(el);
187
188
 
188
- expect(el.value).to.equal('TEST');
189
+ expect(el.value).to.equal("TEST");
189
190
 
190
191
  el.remove();
191
192
  });
package/src/lib/attr.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { metadataStore } from './metadata.js';
1
+ import { metadataStore } from "./metadata.js";
2
2
 
3
3
  export interface AttrOpts {
4
4
  name?: string;
@@ -9,7 +9,7 @@ export interface AttrOpts {
9
9
  export function attr(opts?: AttrOpts) {
10
10
  return function attrDecorator<This extends HTMLElement>(
11
11
  { get, set }: ClassAccessorDecoratorTarget<This, unknown>,
12
- ctx: ClassAccessorDecoratorContext<This>
12
+ ctx: ClassAccessorDecoratorContext<This>,
13
13
  ): ClassAccessorDecoratorResult<This, any> {
14
14
  const attrName = opts?.name ?? parseAttrName(ctx.name);
15
15
  const meta = metadataStore.read<This>(ctx.metadata);
@@ -20,7 +20,7 @@ export function attr(opts?: AttrOpts) {
20
20
  observe: opts?.observed ?? true,
21
21
  reflect,
22
22
  getPropValue: get,
23
- setPropValue: set
23
+ setPropValue: set,
24
24
  });
25
25
 
26
26
  return {
@@ -28,7 +28,7 @@ export function attr(opts?: AttrOpts) {
28
28
  if (reflect) {
29
29
  if (value === true) {
30
30
  if (!this.hasAttribute(attrName)) {
31
- this.setAttribute(attrName, '');
31
+ this.setAttribute(attrName, "");
32
32
  }
33
33
  } else if (value === false) {
34
34
  if (this.hasAttribute(attrName)) {
@@ -44,7 +44,7 @@ export function attr(opts?: AttrOpts) {
44
44
  }
45
45
 
46
46
  set.call(this, value);
47
- }
47
+ },
48
48
  };
49
49
  };
50
50
  }
@@ -52,15 +52,15 @@ export function attr(opts?: AttrOpts) {
52
52
  function parseAttrName(val: string | symbol): string {
53
53
  let value: string;
54
54
 
55
- if (typeof val === 'symbol') {
55
+ if (typeof val === "symbol") {
56
56
  if (val.description) {
57
57
  value = val.description;
58
58
  } else {
59
- throw new Error('Cannot handle Symbol property without description');
59
+ throw new Error("Cannot handle Symbol property without description");
60
60
  }
61
61
  } else {
62
62
  value = val;
63
63
  }
64
64
 
65
- return value.toLowerCase().replaceAll(' ', '-');
65
+ return value.toLowerCase().replaceAll(" ", "-");
66
66
  }
@@ -1,16 +1,16 @@
1
- import { expect, assert } from 'chai';
1
+ import { assert, expect } from "chai";
2
2
 
3
- import { attr } from './attr.js';
4
- import { element } from './element.js';
5
- import { css, html } from './tags.js';
3
+ import { attr } from "./attr.js";
4
+ import { element } from "./element.js";
5
+ import { css, html } from "./tags.js";
6
6
 
7
- it('should write default value to attribute', async () => {
7
+ it("should write default value to attribute", async () => {
8
8
  @element({
9
- tagName: 'element-1'
9
+ tagName: "element-1",
10
10
  })
11
11
  class MyElement extends HTMLElement {
12
12
  @attr()
13
- accessor value1 = 'hello'; // no attribute
13
+ accessor value1 = "hello"; // no attribute
14
14
 
15
15
  @attr()
16
16
  accessor value2 = 0; // number
@@ -19,17 +19,17 @@ it('should write default value to attribute', async () => {
19
19
  accessor value3 = true; // boolean
20
20
 
21
21
  @attr({ reflect: false })
22
- accessor value4 = 'foo';
22
+ accessor value4 = "foo";
23
23
  }
24
24
 
25
25
  const el = new MyElement();
26
26
 
27
27
  document.body.append(el);
28
28
 
29
- expect(el.getAttribute('value1')).to.equal('hello');
30
- expect(el.getAttribute('value2')).to.equal('0');
31
- expect(el.getAttribute('value3')).to.equal('');
32
- expect(el.getAttribute('value4')).to.equal(null);
29
+ expect(el.getAttribute("value1")).to.equal("hello");
30
+ expect(el.getAttribute("value2")).to.equal("0");
31
+ expect(el.getAttribute("value3")).to.equal("");
32
+ expect(el.getAttribute("value4")).to.equal(null);
33
33
 
34
34
  el.remove();
35
35
  });
@@ -60,10 +60,10 @@ it('should write default value to attribute', async () => {
60
60
  // ]);
61
61
  // });
62
62
 
63
- it('should attach shadow root when the shadow property exists', async () => {
63
+ it("should attach shadow root when the shadow property exists", async () => {
64
64
  @element({
65
- tagName: 'element-3',
66
- shadowDom: []
65
+ tagName: "element-3",
66
+ shadowDom: [],
67
67
  })
68
68
  class MyElement extends HTMLElement {}
69
69
 
@@ -72,9 +72,9 @@ it('should attach shadow root when the shadow property exists', async () => {
72
72
  expect(el.shadowRoot).to.be.instanceOf(ShadowRoot);
73
73
  });
74
74
 
75
- it('should apply html and css', async () => {
75
+ it("should apply html and css", async () => {
76
76
  @element({
77
- tagName: 'element-4',
77
+ tagName: "element-4",
78
78
  shadowDom: [
79
79
  css`
80
80
  :host {
@@ -84,30 +84,30 @@ it('should apply html and css', async () => {
84
84
  html`<slot></slot>`,
85
85
  {
86
86
  apply(el) {
87
- const div = document.createElement('div');
88
- div.innerHTML = 'hello world';
87
+ const div = document.createElement("div");
88
+ div.innerHTML = "hello world";
89
89
 
90
90
  el.append(div);
91
- }
92
- }
93
- ]
91
+ },
92
+ },
93
+ ],
94
94
  })
95
95
  class MyElement extends HTMLElement {}
96
96
 
97
97
  const el = new MyElement();
98
98
 
99
- expect(el.shadowRoot!.adoptedStyleSheets.length).to.equal(1);
100
- expect(el.shadowRoot!.innerHTML).to.equal(`<slot></slot>`);
101
- expect(el.innerHTML).to.equal(`<div>hello world</div>`);
99
+ expect(el.shadowRoot?.adoptedStyleSheets.length).to.equal(1);
100
+ expect(el.shadowRoot?.innerHTML).to.equal("<slot></slot>");
101
+ expect(el.innerHTML).to.equal("<div>hello world</div>");
102
102
  });
103
103
 
104
- it('should the correct shadow dom mode', async () => {
104
+ it("should the correct shadow dom mode", async () => {
105
105
  @element({
106
- tagName: 'element-5',
106
+ tagName: "element-5",
107
107
  shadowDom: [],
108
108
  shadowDomOpts: {
109
- mode: 'closed'
110
- }
109
+ mode: "closed",
110
+ },
111
111
  })
112
112
  class MyElement extends HTMLElement {}
113
113
 
@@ -1,5 +1,5 @@
1
- import { AttrMetadata, metadataStore } from './metadata.js';
2
- import { ShadowResult } from './result.js';
1
+ import { type AttrMetadata, metadataStore } from "./metadata.js";
2
+ import type { ShadowResult } from "./result.js";
3
3
 
4
4
  export interface ElementOpts {
5
5
  tagName?: string;
@@ -27,27 +27,31 @@ export function element<T extends ElementConstructor>(opts?: ElementOpts) {
27
27
  [Base.name]: class extends Base {
28
28
  static observedAttributes: string[] = Array.from(meta.attrs.keys());
29
29
 
30
- #removeListeners: Set<Function> = new Set();
30
+ #abortController: AbortController | null = null;
31
31
 
32
32
  constructor(...args: any[]) {
33
33
  super(...args);
34
34
 
35
35
  if (opts?.shadowDom) {
36
36
  if (!this.shadowRoot) {
37
- this.attachShadow(opts.shadowDomOpts ?? { mode: 'open' });
37
+ this.attachShadow(opts.shadowDomOpts ?? { mode: "open" });
38
38
  }
39
39
 
40
- for (let res of opts.shadowDom) {
40
+ for (const res of opts.shadowDom) {
41
41
  res.apply(this);
42
42
  }
43
43
  }
44
44
 
45
- for (let cb of meta.onReady) {
45
+ for (const cb of meta.onReady) {
46
46
  cb.call(this);
47
47
  }
48
48
  }
49
49
 
50
- attributeChangedCallback(name: string, oldValue: string, newValue: string) {
50
+ attributeChangedCallback(
51
+ name: string,
52
+ oldValue: string,
53
+ newValue: string,
54
+ ) {
51
55
  const attr = meta.attrs.get(name);
52
56
  const cbs = meta.attrChanges.get(name);
53
57
 
@@ -55,10 +59,10 @@ export function element<T extends ElementConstructor>(opts?: ElementOpts) {
55
59
  if (oldValue !== newValue) {
56
60
  const ogValue = attr.getPropValue.call(this);
57
61
 
58
- if (newValue === '') {
62
+ if (newValue === "") {
59
63
  // treat as boolean
60
64
  attr.setPropValue.call(this, true);
61
- } else if (typeof ogValue === 'number') {
65
+ } else if (typeof ogValue === "number") {
62
66
  // treat as number
63
67
  attr.setPropValue.call(this, Number(newValue));
64
68
  } else {
@@ -68,29 +72,29 @@ export function element<T extends ElementConstructor>(opts?: ElementOpts) {
68
72
  }
69
73
 
70
74
  if (cbs) {
71
- for (let cb of cbs) {
75
+ for (const cb of cbs) {
72
76
  cb.call(this, oldValue, newValue);
73
77
  }
74
78
  }
75
79
 
76
- if (super.attributeChangedCallback) {
77
- super.attributeChangedCallback(name, oldValue, newValue);
80
+ if (attr.observe) {
81
+ if (super.attributeChangedCallback) {
82
+ super.attributeChangedCallback(name, oldValue, newValue);
83
+ }
78
84
  }
79
85
  }
80
86
  }
81
87
 
82
88
  connectedCallback() {
83
89
  if (this.isConnected) {
84
- for (let { event, cb, selector } of meta.listeners) {
90
+ for (const { event, cb, selector } of meta.listeners) {
85
91
  const root = selector(this);
86
92
 
87
93
  if (root) {
88
- const thisCb = cb.bind(this);
89
-
90
- root.addEventListener(event, thisCb);
94
+ this.#abortController = new AbortController();
91
95
 
92
- this.#removeListeners.add(() => {
93
- root.removeEventListener(event, thisCb);
96
+ root.addEventListener(event, cb.bind(this), {
97
+ signal: this.#abortController.signal,
94
98
  });
95
99
  } else {
96
100
  throw new Error(`could not add listener to ${root}`);
@@ -106,33 +110,37 @@ export function element<T extends ElementConstructor>(opts?: ElementOpts) {
106
110
  }
107
111
 
108
112
  disconnectedCallback(): void {
109
- for (let remove of this.#removeListeners) {
110
- remove();
113
+ if (this.#abortController) {
114
+ this.#abortController.abort();
115
+ this.#abortController = null;
111
116
  }
112
117
 
113
118
  if (super.disconnectedCallback) {
114
119
  super.disconnectedCallback();
115
120
  }
116
121
  }
117
- }
122
+ },
118
123
  };
119
124
 
120
125
  return def[Base.name];
121
126
  };
122
127
  }
123
128
 
124
- function reflectAttributeValues<T extends HTMLElement>(el: T, attrs: AttrMetadata) {
125
- for (let [attrName, { getPropValue, reflect }] of attrs) {
129
+ function reflectAttributeValues<T extends HTMLElement>(
130
+ el: T,
131
+ attrs: AttrMetadata,
132
+ ) {
133
+ for (const [attrName, { getPropValue, reflect }] of attrs) {
126
134
  if (reflect) {
127
135
  const value = getPropValue.call(el);
128
136
 
129
137
  // reflect values back to attributes
130
- if (value !== null && value !== undefined && value !== '') {
131
- if (typeof value === 'boolean') {
138
+ if (value !== null && value !== undefined && value !== "") {
139
+ if (typeof value === "boolean") {
132
140
  if (value === true) {
133
141
  // set boolean attribute
134
142
  if (!el.hasAttribute(attrName)) {
135
- el.setAttribute(attrName, '');
143
+ el.setAttribute(attrName, "");
136
144
  }
137
145
  }
138
146
  } else {
@@ -1,24 +1,24 @@
1
- import { assert } from 'chai';
2
- import { element } from './element.js';
3
- import { ready } from './lifecycle.js';
1
+ import { assert } from "chai";
2
+ import { element } from "./element.js";
3
+ import { ready } from "./lifecycle.js";
4
4
 
5
- it('should call all callbacks when template is ready', () => {
5
+ it("should call all callbacks when template is ready", () => {
6
6
  @element({
7
- tagName: 'template-ready-1'
7
+ tagName: "template-ready-1",
8
8
  })
9
9
  class MyElement extends HTMLElement {
10
10
  callCount: Record<string, number> = {};
11
11
 
12
12
  @ready()
13
13
  onTemplateReady1() {
14
- this.callCount['onTemplateReady1'] ??= 0;
15
- this.callCount['onTemplateReady1']++;
14
+ this.callCount.onTemplateReady1 ??= 0;
15
+ this.callCount.onTemplateReady1++;
16
16
  }
17
17
 
18
18
  @ready()
19
19
  onTemplateReady2() {
20
- this.callCount['onTemplateReady2'] ??= 0;
21
- this.callCount['onTemplateReady2']++;
20
+ this.callCount.onTemplateReady2 ??= 0;
21
+ this.callCount.onTemplateReady2++;
22
22
  }
23
23
  }
24
24
 
@@ -26,6 +26,6 @@ it('should call all callbacks when template is ready', () => {
26
26
 
27
27
  assert.deepEqual(el.callCount, {
28
28
  onTemplateReady1: 1,
29
- onTemplateReady2: 1
29
+ onTemplateReady2: 1,
30
30
  });
31
31
  });
@@ -1,7 +1,10 @@
1
- import { metadataStore } from './metadata.js';
1
+ import { metadataStore } from "./metadata.js";
2
2
 
3
3
  export function ready() {
4
- return function readyDecorator(val: Function, ctx: ClassMethodDecoratorContext): void {
4
+ return function readyDecorator(
5
+ val: () => void,
6
+ ctx: ClassMethodDecoratorContext,
7
+ ): void {
5
8
  const metadata = metadataStore.read(ctx.metadata);
6
9
 
7
10
  metadata.onReady.add(val);