@joist/element 3.9.1 → 4.0.0-next.10
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.
- package/README.md +67 -29
- package/package.json +5 -4
- package/src/lib/attr.test.ts +122 -48
- package/src/lib/attr.ts +61 -34
- package/src/lib/element.test.ts +89 -16
- package/src/lib/element.ts +74 -38
- package/src/lib/lifecycle.test.ts +31 -0
- package/src/lib/lifecycle.ts +9 -0
- package/src/lib/listen.test.ts +88 -0
- package/src/lib/listen.ts +27 -4
- package/src/lib/metadata.ts +17 -3
- package/src/lib/query.test.ts +53 -0
- package/src/lib/query.ts +37 -0
- package/src/lib/result.ts +2 -26
- package/src/lib/tags.ts +22 -64
- package/src/lib/template.test.ts +95 -0
- package/src/lib/template.ts +115 -0
- package/src/lib.ts +3 -3
- package/target/lib/attr.d.ts +4 -1
- package/target/lib/attr.js +49 -28
- package/target/lib/attr.js.map +1 -1
- package/target/lib/attr.test.js +277 -147
- package/target/lib/attr.test.js.map +1 -1
- package/target/lib/element.d.ts +6 -1
- package/target/lib/element.js +58 -29
- package/target/lib/element.js.map +1 -1
- package/target/lib/element.test.js +186 -64
- package/target/lib/element.test.js.map +1 -1
- package/target/lib/lifecycle.d.ts +1 -0
- package/target/lib/lifecycle.js +8 -0
- package/target/lib/lifecycle.js.map +1 -0
- package/target/lib/lifecycle.test.js +48 -0
- package/target/lib/lifecycle.test.js.map +1 -0
- package/target/lib/listen.d.ts +2 -1
- package/target/lib/listen.js +21 -3
- package/target/lib/listen.js.map +1 -1
- package/target/lib/listen.test.js +159 -0
- package/target/lib/listen.test.js.map +1 -0
- package/target/lib/metadata.d.ts +14 -3
- package/target/lib/metadata.js +2 -2
- package/target/lib/metadata.js.map +1 -1
- package/target/lib/query.d.ts +9 -0
- package/target/lib/query.js +24 -0
- package/target/lib/query.js.map +1 -0
- package/target/lib/query.test.js +78 -0
- package/target/lib/query.test.js.map +1 -0
- package/target/lib/result.d.ts +2 -8
- package/target/lib/result.js +1 -19
- package/target/lib/result.js.map +1 -1
- package/target/lib/tags.d.ts +10 -20
- package/target/lib/tags.js +17 -29
- package/target/lib/tags.js.map +1 -1
- package/target/lib/template.d.ts +9 -0
- package/target/lib/template.js +83 -0
- package/target/lib/template.js.map +1 -0
- package/target/lib/template.test.d.ts +1 -0
- package/target/lib/template.test.js +70 -0
- package/target/lib/template.test.js.map +1 -0
- package/target/lib.d.ts +3 -3
- package/target/lib.js +3 -3
- package/target/lib.js.map +1 -1
- package/src/lib/shadow.test.ts +0 -40
- package/src/lib/shadow.ts +0 -16
- package/src/lib/tag-name.test.ts +0 -13
- package/src/lib/tag-name.ts +0 -10
- package/src/lib/tags.test.ts +0 -28
- package/target/lib/shadow.d.ts +0 -2
- package/target/lib/shadow.js +0 -10
- package/target/lib/shadow.js.map +0 -1
- package/target/lib/shadow.test.js +0 -69
- package/target/lib/shadow.test.js.map +0 -1
- package/target/lib/tag-name.d.ts +0 -1
- package/target/lib/tag-name.js +0 -6
- package/target/lib/tag-name.js.map +0 -1
- package/target/lib/tag-name.test.js +0 -36
- package/target/lib/tag-name.test.js.map +0 -1
- package/target/lib/tags.test.js +0 -23
- package/target/lib/tags.test.js.map +0 -1
- /package/target/lib/{shadow.test.d.ts → lifecycle.test.d.ts} +0 -0
- /package/target/lib/{tag-name.test.d.ts → listen.test.d.ts} +0 -0
- /package/target/lib/{tags.test.d.ts → query.test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,42 +1,80 @@
|
|
|
1
1
|
# Element
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Utilities for building web compnennts. Especially targeted at
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Custom Element](#custom-element)
|
|
9
|
+
- [Attributes](#attributes)
|
|
10
|
+
- [Template](#template)
|
|
11
|
+
- [Styles](#styles)
|
|
12
|
+
- [Listeners](#listeners)
|
|
13
|
+
- [Queries](#queries)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
6
16
|
|
|
7
17
|
```BASH
|
|
8
|
-
npm i @joist/element
|
|
18
|
+
npm i @joist/element@next
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Custom Element
|
|
22
|
+
|
|
23
|
+
To define a custom element decorate your custom element class and add a tagName
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
@element({
|
|
27
|
+
tagName: 'my-element'
|
|
28
|
+
})
|
|
29
|
+
export class MyElement extends HTMLElement {}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Attributes
|
|
33
|
+
|
|
34
|
+
Attributes can be managed using the `@attr` decorator. This decorator will read attribute values and and write properties back to attributes;
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
@element({
|
|
38
|
+
tagName: 'my-element'
|
|
39
|
+
})
|
|
40
|
+
export class MyElement extends HTMLElement {
|
|
41
|
+
@attr()
|
|
42
|
+
accessor greeting = 'Hello World';
|
|
43
|
+
}
|
|
9
44
|
```
|
|
10
45
|
|
|
11
|
-
|
|
46
|
+
## Template
|
|
12
47
|
|
|
13
|
-
|
|
14
|
-
import { tagName, shadow, css, html, attr, listen, element } from '@joist/element';
|
|
48
|
+
Joist ships with a very simple template library. It is designed to be very small and is only responsible for updating text in different DOM nodes.
|
|
15
49
|
|
|
16
|
-
|
|
50
|
+
```ts
|
|
51
|
+
@element({
|
|
52
|
+
tagName: 'my-element',
|
|
53
|
+
shadow: [
|
|
54
|
+
html`
|
|
55
|
+
<h1 #:bind="greeting" #:hidden="!greeting"></h1>
|
|
56
|
+
|
|
57
|
+
<ul>
|
|
58
|
+
<li #:bind="items.0"></li>
|
|
59
|
+
<li #:bind="items.1"></li>
|
|
60
|
+
<li #:bind="items.2"></li>
|
|
61
|
+
<li #:bind="items.3"></li>
|
|
62
|
+
<li #:bind="items.4"></li>
|
|
63
|
+
</ul>
|
|
64
|
+
`
|
|
65
|
+
]
|
|
66
|
+
})
|
|
17
67
|
export class MyElement extends HTMLElement {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// apply html to shadow dom
|
|
30
|
-
@shadow template = html`
|
|
31
|
-
<slot></slot>
|
|
32
|
-
`;
|
|
33
|
-
|
|
34
|
-
// define attributes
|
|
35
|
-
@attr accessor value = 0;
|
|
36
|
-
|
|
37
|
-
// listen for events
|
|
38
|
-
@listen('click') onClick() {
|
|
39
|
-
console.log('clicked!')
|
|
68
|
+
@attr()
|
|
69
|
+
accessor greeting = 'Hello World';
|
|
70
|
+
|
|
71
|
+
items = ['first', 'second', 'third', 'fourth', 'fifth'];
|
|
72
|
+
|
|
73
|
+
#render = template();
|
|
74
|
+
|
|
75
|
+
@ready()
|
|
76
|
+
onReady() {
|
|
77
|
+
this.#render();
|
|
40
78
|
}
|
|
41
79
|
}
|
|
42
80
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joist/element",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-next.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./target/lib.js",
|
|
6
6
|
"module": "./target/lib.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"import": "./target/lib.js"
|
|
10
10
|
},
|
|
11
11
|
"./*": {
|
|
12
|
-
"import": "./target/lib
|
|
12
|
+
"import": "./target/lib"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"description": "Intelligently apply styles to WebComponents",
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/
|
|
23
|
+
"url": "git+https://github.com/joist-framework/joist.git"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|
|
26
26
|
"TypeScript",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"author": "deebloo",
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"bugs": {
|
|
34
|
-
"url": "https://github.com/
|
|
34
|
+
"url": "https://github.com/joist-framework/joist/issues"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"test": {
|
|
58
58
|
"command": "wtr --config wtr.config.mjs",
|
|
59
59
|
"files": [
|
|
60
|
+
"vitest.config.js",
|
|
60
61
|
"target/**"
|
|
61
62
|
],
|
|
62
63
|
"output": [],
|
package/src/lib/attr.test.ts
CHANGED
|
@@ -1,64 +1,138 @@
|
|
|
1
|
-
import { expect
|
|
1
|
+
import { expect } from 'chai';
|
|
2
2
|
|
|
3
3
|
import { attr } from './attr.js';
|
|
4
|
+
import { element } from './element.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
6
|
+
it('should read and parse the correct values', () => {
|
|
7
|
+
@element({
|
|
8
|
+
tagName: 'attr-test-1'
|
|
9
|
+
})
|
|
10
|
+
class MyElement extends HTMLElement {
|
|
11
|
+
@attr()
|
|
12
|
+
accessor value1 = 100; // no attribute
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
@attr()
|
|
15
|
+
accessor value2 = 0; // number
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
);
|
|
17
|
+
@attr()
|
|
18
|
+
accessor value3 = false; // boolean
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
expect(el.value4).to.equal('world');
|
|
24
|
-
});
|
|
20
|
+
@attr()
|
|
21
|
+
accessor value4 = 'hello'; // string
|
|
22
|
+
}
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@attr accessor value3 = '';
|
|
31
|
-
}
|
|
24
|
+
const container = document.createElement('div');
|
|
25
|
+
container.innerHTML = /*html*/ `
|
|
26
|
+
<attr-test-1 value2="2" value3 value4="world"></attr-test-1>
|
|
27
|
+
`;
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
document.body.append(container);
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
const el = document.querySelector('attr-test-1') as MyElement;
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
expect(el.value1).to.equal(100);
|
|
34
|
+
expect(el.value2).to.equal(2);
|
|
35
|
+
expect(el.value3).to.equal(true);
|
|
36
|
+
expect(el.value4).to.equal('world');
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
container.remove();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should not write falsy props to attributes', async () => {
|
|
42
|
+
@element({
|
|
43
|
+
tagName: 'attr-test-2'
|
|
44
|
+
})
|
|
45
|
+
class MyElement extends HTMLElement {
|
|
46
|
+
@attr()
|
|
47
|
+
accessor value1 = undefined;
|
|
48
|
+
|
|
49
|
+
@attr()
|
|
50
|
+
accessor value2 = null;
|
|
51
|
+
|
|
52
|
+
@attr()
|
|
53
|
+
accessor value3 = '';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const el = new MyElement();
|
|
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;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should update attributes when props are changed', async () => {
|
|
64
|
+
@element({
|
|
65
|
+
tagName: 'attr-test-3'
|
|
66
|
+
})
|
|
67
|
+
class MyElement extends HTMLElement {
|
|
68
|
+
@attr()
|
|
69
|
+
accessor value1 = 'hello'; // no attribute
|
|
70
|
+
|
|
71
|
+
@attr()
|
|
72
|
+
accessor value2 = 0; // number
|
|
73
|
+
|
|
74
|
+
@attr()
|
|
75
|
+
accessor value3 = true; // boolean
|
|
49
76
|
|
|
50
|
-
|
|
77
|
+
@attr()
|
|
78
|
+
accessor value4 = false; // boolean
|
|
79
|
+
}
|
|
51
80
|
|
|
52
|
-
|
|
81
|
+
const el = new MyElement();
|
|
53
82
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
83
|
+
el.value1 = 'world';
|
|
84
|
+
el.value2 = 100;
|
|
85
|
+
el.value3 = false;
|
|
86
|
+
el.value4 = true;
|
|
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;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should normalize attribute names', async () => {
|
|
95
|
+
const value3 = Symbol('Value from SYMBOL');
|
|
96
|
+
|
|
97
|
+
@element({
|
|
98
|
+
tagName: 'attr-test-4'
|
|
99
|
+
})
|
|
100
|
+
class MyElement extends HTMLElement {
|
|
101
|
+
@attr()
|
|
102
|
+
accessor Value1 = 'hello';
|
|
103
|
+
|
|
104
|
+
@attr()
|
|
105
|
+
accessor ['Value 2'] = 0;
|
|
106
|
+
|
|
107
|
+
@attr()
|
|
108
|
+
accessor [value3] = true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const el = new MyElement();
|
|
112
|
+
|
|
113
|
+
document.body.append(el);
|
|
114
|
+
|
|
115
|
+
expect([...el.attributes].map((attr) => attr.name)).to.deep.equal([
|
|
116
|
+
'value1',
|
|
117
|
+
'value-2',
|
|
118
|
+
'value-from-symbol'
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
el.remove();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should throw an error for symbols with no description', async () => {
|
|
125
|
+
expect(() => {
|
|
126
|
+
const value = Symbol();
|
|
127
|
+
|
|
128
|
+
@element({
|
|
129
|
+
tagName: 'attr-test-4'
|
|
130
|
+
})
|
|
131
|
+
class MyElement extends HTMLElement {
|
|
132
|
+
@attr()
|
|
133
|
+
accessor [value] = true;
|
|
134
|
+
}
|
|
58
135
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
expect(el.hasAttribute('value3')).to.be.false;
|
|
62
|
-
expect(el.hasAttribute('value4')).to.be.true;
|
|
63
|
-
});
|
|
136
|
+
new MyElement();
|
|
137
|
+
}).to.throw('Cannot handle Symbol property without description');
|
|
64
138
|
});
|
package/src/lib/attr.ts
CHANGED
|
@@ -1,46 +1,73 @@
|
|
|
1
1
|
import { metadataStore } from './metadata.js';
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
this.setAttribute(name, '');
|
|
15
|
-
} else if (value === false) {
|
|
16
|
-
this.removeAttribute(name);
|
|
17
|
-
} else {
|
|
18
|
-
this.setAttribute(name, String(value));
|
|
19
|
-
}
|
|
3
|
+
export interface AttrOpts {
|
|
4
|
+
observed?: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function attr(opts?: AttrOpts) {
|
|
8
|
+
return function attrDecorator<This extends HTMLElement>(
|
|
9
|
+
{ get, set }: ClassAccessorDecoratorTarget<This, unknown>,
|
|
10
|
+
ctx: ClassAccessorDecoratorContext<This>
|
|
11
|
+
): ClassAccessorDecoratorResult<This, any> {
|
|
12
|
+
const attrName = parseAttrName(ctx.name);
|
|
13
|
+
const meta = metadataStore.read(ctx.metadata);
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
meta.attrs.push({
|
|
16
|
+
propName: ctx.name,
|
|
17
|
+
attrName,
|
|
18
|
+
observe: opts?.observed ?? true
|
|
19
|
+
});
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
|
|
21
|
+
return {
|
|
22
|
+
set(value: unknown) {
|
|
23
|
+
if (value === true) {
|
|
24
|
+
this.setAttribute(attrName, '');
|
|
25
|
+
} else if (value === false) {
|
|
26
|
+
this.removeAttribute(attrName);
|
|
27
|
+
} else {
|
|
28
|
+
this.setAttribute(attrName, String(value));
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
set.call(this, value);
|
|
32
|
+
},
|
|
33
|
+
get() {
|
|
34
|
+
const ogValue = get.call(this);
|
|
35
|
+
const attr = this.getAttribute(attrName);
|
|
36
|
+
|
|
37
|
+
if (attr !== null) {
|
|
38
|
+
// treat as boolean
|
|
39
|
+
if (attr === '') {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// treat as number
|
|
44
|
+
if (typeof ogValue === 'number') {
|
|
45
|
+
return Number(attr);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// treat as string
|
|
49
|
+
return attr;
|
|
36
50
|
}
|
|
37
51
|
|
|
38
|
-
//
|
|
39
|
-
return
|
|
52
|
+
// no readable value return original
|
|
53
|
+
return ogValue;
|
|
40
54
|
}
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function parseAttrName(val: string | symbol): string {
|
|
60
|
+
let value: string;
|
|
41
61
|
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
if (typeof val === 'symbol') {
|
|
63
|
+
if (val.description) {
|
|
64
|
+
value = val.description;
|
|
65
|
+
} else {
|
|
66
|
+
throw new Error('Cannot handle Symbol property without description');
|
|
44
67
|
}
|
|
45
|
-
}
|
|
68
|
+
} else {
|
|
69
|
+
value = val;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return value.toLowerCase().replaceAll(' ', '-');
|
|
46
73
|
}
|
package/src/lib/element.test.ts
CHANGED
|
@@ -1,24 +1,97 @@
|
|
|
1
|
-
import { expect
|
|
1
|
+
import { expect } from 'chai';
|
|
2
2
|
|
|
3
3
|
import { attr } from './attr.js';
|
|
4
4
|
import { element } from './element.js';
|
|
5
|
-
import {
|
|
5
|
+
import { css, html } from './tags.js';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@attr accessor value3 = true; // boolean
|
|
16
|
-
}
|
|
15
|
+
@attr()
|
|
16
|
+
accessor value2 = 0; // number
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
@attr()
|
|
19
|
+
accessor value3 = true; // boolean
|
|
20
|
+
}
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const el = new MyElement();
|
|
23
|
+
|
|
24
|
+
document.body.append(el);
|
|
25
|
+
|
|
26
|
+
expect(el.getAttribute('value1')).to.equal('hello');
|
|
27
|
+
expect(el.getAttribute('value2')).to.equal('0');
|
|
28
|
+
expect(el.getAttribute('value3')).to.equal('');
|
|
29
|
+
|
|
30
|
+
el.remove();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should register attributes', async () => {
|
|
34
|
+
@element({
|
|
35
|
+
tagName: 'element-2'
|
|
36
|
+
})
|
|
37
|
+
class MyElement extends HTMLElement {
|
|
38
|
+
@attr()
|
|
39
|
+
accessor value1 = 'hello'; // no attribute
|
|
40
|
+
|
|
41
|
+
@attr()
|
|
42
|
+
accessor value2 = 0; // number
|
|
43
|
+
|
|
44
|
+
@attr()
|
|
45
|
+
accessor value3 = true; // boolean
|
|
46
|
+
|
|
47
|
+
@attr({ observed: false }) // should be filtered out
|
|
48
|
+
accessor value4 = 'hello world';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
expect(Reflect.get(MyElement, 'observedAttributes')).to.deep.equal([
|
|
52
|
+
'value1',
|
|
53
|
+
'value2',
|
|
54
|
+
'value3'
|
|
55
|
+
]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should attach shadow root when the shadow property exists', async () => {
|
|
59
|
+
@element({
|
|
60
|
+
tagName: 'element-3',
|
|
61
|
+
shadow: []
|
|
62
|
+
})
|
|
63
|
+
class MyElement extends HTMLElement {}
|
|
64
|
+
|
|
65
|
+
const el = new MyElement();
|
|
66
|
+
|
|
67
|
+
expect(el.shadowRoot).to.be.instanceOf(ShadowRoot);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should apply html and css', async () => {
|
|
71
|
+
@element({
|
|
72
|
+
tagName: 'element-4',
|
|
73
|
+
shadow: [
|
|
74
|
+
css`
|
|
75
|
+
:host {
|
|
76
|
+
display: contents;
|
|
77
|
+
}
|
|
78
|
+
`,
|
|
79
|
+
html`<slot></slot>`,
|
|
80
|
+
{
|
|
81
|
+
apply(el) {
|
|
82
|
+
const div = document.createElement('div');
|
|
83
|
+
div.innerHTML = 'hello world';
|
|
84
|
+
|
|
85
|
+
el.append(div);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
})
|
|
90
|
+
class MyElement extends HTMLElement {}
|
|
91
|
+
|
|
92
|
+
const el = new MyElement();
|
|
93
|
+
|
|
94
|
+
expect(el.shadowRoot!.adoptedStyleSheets.length).to.equal(1);
|
|
95
|
+
expect(el.shadowRoot!.innerHTML).to.equal(`<slot></slot>`);
|
|
96
|
+
expect(el.innerHTML).to.equal(`<div>hello world</div>`);
|
|
24
97
|
});
|