@joist/element 4.0.0-next.3 → 4.0.0-next.30

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 (67) hide show
  1. package/README.md +102 -15
  2. package/package.json +7 -9
  3. package/src/lib/attr.test.ts +138 -97
  4. package/src/lib/attr.ts +16 -32
  5. package/src/lib/element.test.ts +101 -70
  6. package/src/lib/element.ts +89 -40
  7. package/src/lib/lifecycle.test.ts +31 -0
  8. package/src/lib/lifecycle.ts +9 -0
  9. package/src/lib/listen.test.ts +88 -0
  10. package/src/lib/listen.ts +26 -9
  11. package/src/lib/metadata.ts +18 -7
  12. package/src/lib/query.test.ts +28 -0
  13. package/src/lib/query.ts +31 -0
  14. package/src/lib/result.ts +1 -21
  15. package/src/lib/tags.ts +27 -12
  16. package/src/lib/template.test.ts +123 -0
  17. package/src/lib/template.ts +118 -0
  18. package/src/lib.ts +2 -1
  19. package/target/lib/attr.d.ts +2 -1
  20. package/target/lib/attr.js +15 -24
  21. package/target/lib/attr.js.map +1 -1
  22. package/target/lib/attr.test.js +333 -252
  23. package/target/lib/attr.test.js.map +1 -1
  24. package/target/lib/element.d.ts +24 -11
  25. package/target/lib/element.js +66 -28
  26. package/target/lib/element.js.map +1 -1
  27. package/target/lib/element.test.js +158 -176
  28. package/target/lib/element.test.js.map +1 -1
  29. package/target/lib/lifecycle.d.ts +1 -0
  30. package/target/lib/lifecycle.js +8 -0
  31. package/target/lib/lifecycle.js.map +1 -0
  32. package/target/lib/lifecycle.test.js +48 -0
  33. package/target/lib/lifecycle.test.js.map +1 -0
  34. package/target/lib/listen.d.ts +2 -2
  35. package/target/lib/listen.js +18 -3
  36. package/target/lib/listen.js.map +1 -1
  37. package/target/lib/listen.test.d.ts +1 -0
  38. package/target/lib/listen.test.js +159 -0
  39. package/target/lib/listen.test.js.map +1 -0
  40. package/target/lib/metadata.d.ts +17 -10
  41. package/target/lib/metadata.js +5 -2
  42. package/target/lib/metadata.js.map +1 -1
  43. package/target/lib/query.d.ts +9 -0
  44. package/target/lib/query.js +19 -0
  45. package/target/lib/query.js.map +1 -0
  46. package/target/lib/query.test.d.ts +1 -0
  47. package/target/lib/query.test.js +41 -0
  48. package/target/lib/query.test.js.map +1 -0
  49. package/target/lib/result.d.ts +1 -10
  50. package/target/lib/result.js +1 -22
  51. package/target/lib/result.js.map +1 -1
  52. package/target/lib/tags.d.ts +10 -8
  53. package/target/lib/tags.js +18 -24
  54. package/target/lib/tags.js.map +1 -1
  55. package/target/lib/template.d.ts +11 -0
  56. package/target/lib/template.js +87 -0
  57. package/target/lib/template.js.map +1 -0
  58. package/target/lib/template.test.d.ts +1 -0
  59. package/target/lib/template.test.js +91 -0
  60. package/target/lib/template.test.js.map +1 -0
  61. package/target/lib.d.ts +2 -1
  62. package/target/lib.js +2 -1
  63. package/target/lib.js.map +1 -1
  64. package/src/lib/tags.test.ts +0 -28
  65. package/target/lib/tags.test.js +0 -23
  66. package/target/lib/tags.test.js.map +0 -1
  67. /package/target/lib/{tags.test.d.ts → lifecycle.test.d.ts} +0 -0
@@ -1,86 +1,117 @@
1
- import { expect, fixture, html as litHtml } from '@open-wc/testing';
1
+ import { expect, assert } from 'chai';
2
2
 
3
3
  import { attr } from './attr.js';
4
4
  import { element } from './element.js';
5
5
  import { css, html } from './tags.js';
6
6
 
7
- describe('@element()', () => {
8
- it('should write default value to attribute', async () => {
9
- @element({
10
- tagName: 'element-1'
11
- })
12
- class MyElement extends HTMLElement {
13
- @attr()
14
- accessor value1 = 'hello'; // no attribute
7
+ it('should write default value to attribute', async () => {
8
+ @element({
9
+ tagName: 'element-1'
10
+ })
11
+ class MyElement extends HTMLElement {
12
+ @attr()
13
+ accessor value1 = 'hello'; // no attribute
15
14
 
16
- @attr()
17
- accessor value2 = 0; // number
15
+ @attr()
16
+ accessor value2 = 0; // number
18
17
 
19
- @attr()
20
- accessor value3 = true; // boolean
21
- }
18
+ @attr()
19
+ accessor value3 = true; // boolean
20
+
21
+ @attr({ reflect: false })
22
+ accessor value4 = 'foo';
23
+ }
22
24
 
23
- const el = await fixture<MyElement>(litHtml`<element-1></element-1>`);
25
+ const el = new MyElement();
24
26
 
25
- expect(el.getAttribute('value1')).to.equal('hello');
26
- expect(el.getAttribute('value2')).to.equal('0');
27
- expect(el.getAttribute('value3')).to.equal('');
28
- });
27
+ document.body.append(el);
29
28
 
30
- it('should register attributes', async () => {
31
- @element({
32
- tagName: 'element-2'
33
- })
34
- class MyElement extends HTMLElement {
35
- @attr()
36
- accessor value1 = 'hello'; // no attribute
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);
37
33
 
38
- @attr()
39
- accessor value2 = 0; // number
34
+ el.remove();
35
+ });
40
36
 
41
- @attr()
42
- accessor value3 = true; // boolean
37
+ // TODO: Figure out test
38
+ // it('should register attributes', async () => {
39
+ // @element({
40
+ // tagName: 'element-2'
41
+ // })
42
+ // class MyElement extends HTMLElement {
43
+ // @attr()
44
+ // accessor value1 = 'hello'; // no attribute
45
+
46
+ // @attr()
47
+ // accessor value2 = 0; // number
48
+
49
+ // @attr()
50
+ // accessor value3 = true; // boolean
51
+
52
+ // @attr({ observed: false }) // should be filtered out
53
+ // accessor value4 = 'hello world';
54
+ // }
55
+
56
+ // expect(Reflect.get(MyElement, 'observedAttributes')).to.deep.equal([
57
+ // 'value1',
58
+ // 'value2',
59
+ // 'value3'
60
+ // ]);
61
+ // });
62
+
63
+ it('should attach shadow root when the shadow property exists', async () => {
64
+ @element({
65
+ tagName: 'element-3',
66
+ shadowDom: []
67
+ })
68
+ class MyElement extends HTMLElement {}
69
+
70
+ const el = new MyElement();
71
+
72
+ expect(el.shadowRoot).to.be.instanceOf(ShadowRoot);
73
+ });
43
74
 
44
- @attr({ observe: false }) // should be filtered out
45
- accessor value4 = 'hello world';
75
+ it('should apply html and css', async () => {
76
+ @element({
77
+ tagName: 'element-4',
78
+ shadowDom: [
79
+ css`
80
+ :host {
81
+ display: contents;
82
+ }
83
+ `,
84
+ html`<slot></slot>`,
85
+ {
86
+ apply(el) {
87
+ const div = document.createElement('div');
88
+ div.innerHTML = 'hello world';
89
+
90
+ el.append(div);
91
+ }
92
+ }
93
+ ]
94
+ })
95
+ class MyElement extends HTMLElement {}
96
+
97
+ const el = new MyElement();
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>`);
102
+ });
103
+
104
+ it('should the correct shadow dom mode', async () => {
105
+ @element({
106
+ tagName: 'element-5',
107
+ shadowDom: [],
108
+ shadowDomOpts: {
109
+ mode: 'closed'
46
110
  }
111
+ })
112
+ class MyElement extends HTMLElement {}
113
+
114
+ const el = new MyElement();
47
115
 
48
- expect(Reflect.get(MyElement, 'observedAttributes')).to.deep.equal([
49
- 'value1',
50
- 'value2',
51
- 'value3'
52
- ]);
53
- });
54
-
55
- it('should attach shadow root when the shadow property exists', async () => {
56
- @element({
57
- tagName: 'element-3',
58
- shadow: []
59
- })
60
- class MyElement extends HTMLElement {}
61
-
62
- const el = new MyElement();
63
-
64
- expect(el.shadowRoot).to.be.instanceOf(ShadowRoot);
65
- });
66
-
67
- it('should apply html and css', async () => {
68
- @element({
69
- tagName: 'element-4',
70
- shadow: [
71
- css`
72
- :host {
73
- display: contents;
74
- }
75
- `,
76
- html`<slot></slot>`
77
- ]
78
- })
79
- class MyElement extends HTMLElement {}
80
-
81
- const el = new MyElement();
82
-
83
- expect(el.shadowRoot!.adoptedStyleSheets.length).to.equal(1);
84
- expect(el.shadowRoot!.innerHTML).to.equal(`<slot></slot>`);
85
- });
116
+ assert.equal(el.shadowRoot, null);
86
117
  });
@@ -1,19 +1,21 @@
1
- import { AttrDef, metadataStore } from './metadata.js';
1
+ import { AttrMetadata, metadataStore } from './metadata.js';
2
2
  import { ShadowResult } from './result.js';
3
3
 
4
- export interface ElementOpts<T> {
4
+ export interface ElementOpts {
5
5
  tagName?: string;
6
- shadow?: Array<ShadowResult | ((el: T) => void)>;
6
+ shadowDom?: ShadowResult[];
7
+ shadowDomOpts?: ShadowRootInit;
7
8
  }
8
9
 
9
- export function element<
10
- Target extends CustomElementConstructor,
11
- Instance extends InstanceType<Target>
12
- >(opts?: ElementOpts<Instance>) {
13
- return function elementDecorator(Base: Target, ctx: ClassDecoratorContext<Target>) {
10
+ interface ElementConstructor {
11
+ new (...args: any[]): HTMLElement;
12
+ }
13
+
14
+ export function element<T extends ElementConstructor>(opts?: ElementOpts) {
15
+ return function elementDecorator(Base: T, ctx: ClassDecoratorContext<T>) {
14
16
  const meta = metadataStore.read(ctx.metadata);
15
17
 
16
- ctx.addInitializer(function (this: Target) {
18
+ ctx.addInitializer(function () {
17
19
  if (opts?.tagName) {
18
20
  if (!customElements.get(opts.tagName)) {
19
21
  customElements.define(opts.tagName, this);
@@ -21,56 +23,103 @@ export function element<
21
23
  }
22
24
  });
23
25
 
24
- return class JoistElement extends Base {
25
- static observedAttributes = meta.attrs
26
- .filter(({ observe }) => observe) // filter out attributes that are not to be observed
27
- .map(({ attrName }) => attrName);
26
+ const def = {
27
+ [Base.name]: class extends Base {
28
+ static observedAttributes: string[] = [];
29
+
30
+ static {
31
+ for (let [attrName] of meta.attrs) {
32
+ this.observedAttributes.push(attrName);
33
+ }
34
+ }
35
+
36
+ constructor(...args: any[]) {
37
+ super(...args);
28
38
 
29
- constructor(...args: any[]) {
30
- super(...args);
39
+ if (opts?.shadowDom) {
40
+ if (!this.shadowRoot) {
41
+ this.attachShadow(opts.shadowDomOpts ?? { mode: 'open' });
42
+ }
43
+
44
+ for (let res of opts.shadowDom) {
45
+ res.apply(this);
46
+ }
47
+ }
31
48
 
32
- if (opts?.shadow) {
33
- this.attachShadow({ mode: 'open' });
49
+ for (let { event, cb, selector } of meta.listeners) {
50
+ const root = selector(this);
34
51
 
35
- for (let res of opts.shadow) {
36
- if (typeof res === 'function') {
37
- res(this as unknown as Instance);
52
+ if (root) {
53
+ root.addEventListener(event, cb.bind(this));
38
54
  } else {
39
- res.run(this);
55
+ throw new Error(`could not add listener to ${root}`);
40
56
  }
41
57
  }
58
+
59
+ for (let cb of meta.onReady) {
60
+ cb.call(this);
61
+ }
42
62
  }
43
63
 
44
- for (let [event, { cb, root }] of meta.listeners) {
45
- root(this).addEventListener(event, cb.bind(this));
64
+ connectedCallback() {
65
+ if (this.isConnected) {
66
+ reflectAttributeValues(this, meta.attrs);
67
+
68
+ if (super.connectedCallback) {
69
+ super.connectedCallback();
70
+ }
71
+ }
46
72
  }
47
- }
48
73
 
49
- connectedCallback() {
50
- reflectAttributeValues(this, meta.attrs);
74
+ attributeChangedCallback(name: string, oldValue: string, newValue: string) {
75
+ const attr = meta.attrs.get(name);
76
+
77
+ if (attr) {
78
+ if (oldValue !== newValue) {
79
+ const ogValue = attr.getPropValue.call(this);
51
80
 
52
- if (super.connectedCallback) {
53
- super.connectedCallback();
81
+ if (newValue === '') {
82
+ // treat as boolean
83
+ attr.setPropValue.call(this, true);
84
+ } else if (typeof ogValue === 'number') {
85
+ // treat as number
86
+ attr.setPropValue.call(this, Number(newValue));
87
+ } else {
88
+ // treat as string
89
+ attr.setPropValue.call(this, newValue);
90
+ }
91
+ }
92
+
93
+ if (attr.observe) {
94
+ if (super.attributeChangedCallback) {
95
+ super.attributeChangedCallback(name, oldValue, newValue);
96
+ }
97
+ }
98
+ }
54
99
  }
55
100
  }
56
101
  };
102
+
103
+ return def[Base.name];
57
104
  };
58
105
  }
59
106
 
60
- function reflectAttributeValues(el: HTMLElement, attrs: AttrDef[]) {
61
- for (let { propName, attrName } of attrs) {
62
- const value = Reflect.get(el, propName);
107
+ function reflectAttributeValues<T extends HTMLElement>(el: T, attrs: AttrMetadata) {
108
+ for (let [attrName, { getPropValue, reflect }] of attrs) {
109
+ if (reflect) {
110
+ const value = getPropValue.call(el);
63
111
 
64
- // reflect values back to attributes
65
- if (value !== null && value !== undefined && value !== '') {
66
- if (typeof value === 'boolean') {
67
- if (value === true) {
68
- // set boolean attribute
69
- el.setAttribute(attrName, '');
112
+ // reflect values back to attributes
113
+ if (value !== null && value !== undefined && value !== '') {
114
+ if (typeof value === 'boolean') {
115
+ if (value === true) {
116
+ // set boolean attribute
117
+ el.setAttribute(attrName, '');
118
+ }
119
+ } else {
120
+ // set key/value attribute
121
+ el.setAttribute(attrName, String(value));
70
122
  }
71
- } else {
72
- // set key/value attribute
73
- el.setAttribute(attrName, String(value));
74
123
  }
75
124
  }
76
125
  }
@@ -0,0 +1,31 @@
1
+ import { assert } from 'chai';
2
+ import { element } from './element.js';
3
+ import { ready } from './lifecycle.js';
4
+
5
+ it('should call all callbacks when template is ready', () => {
6
+ @element({
7
+ tagName: 'template-ready-1'
8
+ })
9
+ class MyElement extends HTMLElement {
10
+ callCount: Record<string, number> = {};
11
+
12
+ @ready()
13
+ onTemplateReady1() {
14
+ this.callCount['onTemplateReady1'] ??= 0;
15
+ this.callCount['onTemplateReady1']++;
16
+ }
17
+
18
+ @ready()
19
+ onTemplateReady2() {
20
+ this.callCount['onTemplateReady2'] ??= 0;
21
+ this.callCount['onTemplateReady2']++;
22
+ }
23
+ }
24
+
25
+ const el = new MyElement();
26
+
27
+ assert.deepEqual(el.callCount, {
28
+ onTemplateReady1: 1,
29
+ onTemplateReady2: 1
30
+ });
31
+ });
@@ -0,0 +1,9 @@
1
+ import { metadataStore } from './metadata.js';
2
+
3
+ export function ready() {
4
+ return function readyDecorator(val: Function, ctx: ClassMethodDecoratorContext) {
5
+ const metadata = metadataStore.read(ctx.metadata);
6
+
7
+ metadata.onReady.add(val);
8
+ };
9
+ }
@@ -0,0 +1,88 @@
1
+ import { assert } from 'chai';
2
+
3
+ import { element } from './element.js';
4
+ import { listen } from './listen.js';
5
+
6
+ describe('@listen()', () => {
7
+ it('should add listener to an outer HTMLElement', (done) => {
8
+ @element({
9
+ tagName: 'listener-1'
10
+ })
11
+ class MyElement extends HTMLElement {
12
+ @listen('click')
13
+ onClick(e: Event) {
14
+ assert.equal(e.type, 'click');
15
+
16
+ done();
17
+ }
18
+ }
19
+
20
+ const el = new MyElement();
21
+
22
+ el.dispatchEvent(new Event('click'));
23
+ });
24
+
25
+ it('should add listener to the shadow root if available', (done) => {
26
+ @element({
27
+ tagName: 'listener-2',
28
+ shadowDom: []
29
+ })
30
+ class MyElement extends HTMLElement {
31
+ @listen('click')
32
+ onClick(e: Event) {
33
+ assert.equal(e.type, 'click');
34
+
35
+ done();
36
+ }
37
+ }
38
+
39
+ const el = new MyElement();
40
+
41
+ el.shadowRoot!.dispatchEvent(new Event('click'));
42
+ });
43
+
44
+ it('should restrict argument to an event or an event subtype', (done) => {
45
+ class CustomEvent extends Event {
46
+ test = 'Hello World';
47
+
48
+ constructor() {
49
+ super('customevent');
50
+ }
51
+ }
52
+
53
+ @element({
54
+ tagName: 'listener-3'
55
+ })
56
+ class MyElement extends HTMLElement {
57
+ @listen('customevent')
58
+ onClick(e: CustomEvent) {
59
+ assert.equal(e.type, 'customevent');
60
+
61
+ done();
62
+ }
63
+ }
64
+
65
+ const el = new MyElement();
66
+
67
+ el.dispatchEvent(new CustomEvent());
68
+ });
69
+
70
+ it('should respect a provided selector function', (done) => {
71
+ @element({
72
+ tagName: 'listener-4',
73
+ shadowDom: []
74
+ })
75
+ class MyElement extends HTMLElement {
76
+ @listen('click', (host) => host)
77
+ onClick(e: Event) {
78
+ assert.equal(e.type, 'click');
79
+
80
+ done();
81
+ }
82
+ }
83
+
84
+ const el = new MyElement();
85
+
86
+ el.dispatchEvent(new Event('click'));
87
+ });
88
+ });
package/src/lib/listen.ts CHANGED
@@ -1,15 +1,32 @@
1
- import { ListenerRootSelector, metadataStore } from './metadata.js';
1
+ import { ListenerSelector, metadataStore } from './metadata.js';
2
2
 
3
- export function listen<This extends HTMLElement>(event: string, root?: ListenerRootSelector) {
4
- return function listenDecorator(
5
- value: (e: Event) => void,
6
- ctx: ClassMethodDecoratorContext<This>
7
- ) {
8
- const metadata = metadataStore.read(ctx.metadata);
3
+ export function listen<This extends HTMLElement>(
4
+ event: string,
5
+ selector?: ListenerSelector<This> | string
6
+ ) {
7
+ return function listenDecorator(value: (e: any) => void, ctx: ClassMethodDecoratorContext<This>) {
8
+ const metadata = metadataStore.read<This>(ctx.metadata);
9
9
 
10
- metadata.listeners.set(event, {
10
+ let selectorInternal: ListenerSelector<This> = (el) => el.shadowRoot ?? el;
11
+
12
+ if (selector) {
13
+ if (typeof selector === 'string') {
14
+ selectorInternal = (el: This) => {
15
+ if (el.shadowRoot) {
16
+ return el.shadowRoot.querySelector(selector);
17
+ }
18
+
19
+ return el.querySelector(selector);
20
+ };
21
+ } else {
22
+ selectorInternal = selector;
23
+ }
24
+ }
25
+
26
+ metadata.listeners.push({
27
+ event,
11
28
  cb: value,
12
- root: root ?? ((el: HTMLElement) => el.shadowRoot ?? el)
29
+ selector: selectorInternal
13
30
  });
14
31
  };
15
32
  }
@@ -2,19 +2,30 @@
2
2
 
3
3
  export interface AttrDef {
4
4
  propName: string | symbol;
5
- attrName: string;
6
5
  observe: boolean;
6
+ reflect: boolean;
7
+ getPropValue: Function;
8
+ setPropValue: Function;
7
9
  }
8
10
 
9
- export type ListenerRootSelector = (el: HTMLElement) => HTMLElement | ShadowRoot;
11
+ export type ListenerSelector<T> = (el: T) => Element | ShadowRoot | null;
10
12
 
11
- export class ElementMetadata {
12
- attrs: AttrDef[] = [];
13
- listeners = new Map<string, { cb: (e: Event) => void; root: ListenerRootSelector }>();
13
+ export interface Listener<T> {
14
+ event: string;
15
+ cb: (e: Event) => void;
16
+ selector: ListenerSelector<T>;
14
17
  }
15
18
 
16
- export class MetadataStore extends WeakMap<object, ElementMetadata> {
17
- read(value: object) {
19
+ export class AttrMetadata extends Map<string, AttrDef> {}
20
+
21
+ export class ElementMetadata<T> {
22
+ attrs = new AttrMetadata();
23
+ listeners: Listener<T>[] = [];
24
+ onReady = new Set<Function>();
25
+ }
26
+
27
+ export class MetadataStore extends WeakMap<object, ElementMetadata<unknown>> {
28
+ read<T>(value: object): ElementMetadata<T> {
18
29
  if (!this.has(value)) {
19
30
  this.set(value, new ElementMetadata());
20
31
  }
@@ -0,0 +1,28 @@
1
+ import { expect } from 'chai';
2
+
3
+ import { element } from './element.js';
4
+ import { query } from './query.js';
5
+ import { html } from './tags.js';
6
+
7
+ it('should work', () => {
8
+ @element({
9
+ tagName: 'query-test-1',
10
+ shadowDom: [
11
+ html`
12
+ <form>
13
+ <input id="fname" name="fname" />
14
+ <input id="lname" name="lname" />
15
+ </form>
16
+ `
17
+ ]
18
+ })
19
+ class MyElement extends HTMLElement {
20
+ fname = query<HTMLInputElement>('#fname');
21
+ lname = query<HTMLInputElement>('#lname');
22
+ }
23
+
24
+ const el = new MyElement();
25
+
26
+ expect(el.fname()).to.equal(el.shadowRoot?.querySelector('#fname'));
27
+ expect(el.lname()).to.equal(el.shadowRoot?.querySelector('#lname'));
28
+ });
@@ -0,0 +1,31 @@
1
+ type Tags = keyof HTMLElementTagNameMap;
2
+ type SVGTags = keyof SVGElementTagNameMap;
3
+ type MathTags = keyof MathMLElementTagNameMap;
4
+
5
+ type QueryResult<T> = (updates?: Partial<T>) => T;
6
+
7
+ export function query<K extends Tags>(selectors: K): QueryResult<HTMLElementTagNameMap[K]>;
8
+ export function query<K extends SVGTags>(selectors: K): QueryResult<SVGElementTagNameMap[K]>;
9
+ export function query<K extends MathTags>(selectors: K): QueryResult<MathMLElementTagNameMap[K]>;
10
+ export function query<E extends HTMLElement = HTMLElement>(selectors: string): QueryResult<E>;
11
+ export function query<K extends Tags>(query: K): QueryResult<HTMLElementTagNameMap[K]> {
12
+ let res: HTMLElementTagNameMap[K] | null = null;
13
+
14
+ return function (this: HTMLElement) {
15
+ if (res) {
16
+ return res;
17
+ }
18
+
19
+ if (this.shadowRoot) {
20
+ res = this.shadowRoot.querySelector<K>(query);
21
+ } else {
22
+ res = this.querySelector<K>(query);
23
+ }
24
+
25
+ if (!res) {
26
+ throw new Error('could not find element');
27
+ }
28
+
29
+ return res;
30
+ };
31
+ }
package/src/lib/result.ts CHANGED
@@ -1,23 +1,3 @@
1
1
  export interface ShadowResult {
2
- run(el: HTMLElement): void;
3
- }
4
-
5
- export abstract class JoistShadowResult implements ShadowResult {
6
- strings;
7
- values;
8
-
9
- constructor(raw: TemplateStringsArray, ...values: any[]) {
10
- this.strings = raw;
11
- this.values = values;
12
- }
13
-
14
- run(el: HTMLElement) {
15
- if (!el.shadowRoot) {
16
- throw new Error('ShadowResult has not been applied');
17
- }
18
-
19
- this.setup(el.shadowRoot);
20
- }
21
-
22
- abstract setup(root: ShadowRoot): void;
2
+ apply(el: Element): void;
23
3
  }