@webtides/element-js 1.0.0 → 1.1.0
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/CHANGELOG.md +140 -90
- package/README.md +3 -3
- package/docs/README.md +70 -89
- package/docs/concepts/classes.md +37 -66
- package/docs/concepts/hierarchy.md +29 -31
- package/docs/concepts/lifecycle.md +9 -23
- package/docs/concepts/reactivity.md +1 -3
- package/docs/features/computed-properties.md +13 -16
- package/docs/features/dependency-injection-context-protocol.md +75 -87
- package/docs/features/global-styles.md +1 -1
- package/docs/features/methods.md +14 -15
- package/docs/features/properties.md +21 -33
- package/docs/features/refs.md +23 -31
- package/docs/features/renderless.md +31 -37
- package/docs/features/store.md +63 -78
- package/docs/features/templates.md +4 -1
- package/docs/features/watch.md +28 -35
- package/docs/getting-started/upgrade-to-v1.md +16 -0
- package/docs/guide/guide.md +10 -22
- package/index.js +29 -2
- package/package.json +62 -62
- package/src/BaseElement.js +631 -631
- package/src/StyledElement.js +104 -104
- package/src/TemplateElement.js +53 -53
- package/src/dom-parts/AttributePart.js +116 -116
- package/src/dom-parts/ChildNodePart.js +288 -288
- package/src/dom-parts/NodePart.js +27 -27
- package/src/dom-parts/Part.js +6 -6
- package/src/dom-parts/TemplatePart.js +119 -119
- package/src/dom-parts/TemplateResult.js +270 -270
- package/src/dom-parts/directives.js +105 -48
- package/src/dom-parts/html.js +1 -1
- package/src/dom-parts/render.js +6 -6
- package/src/util/AttributeParser.js +47 -47
- package/src/util/DOMHelper.js +190 -190
- package/src/util/Directive.js +31 -31
- package/src/util/GlobalStylesStore.js +56 -53
- package/src/util/SerializeStateHelper.js +56 -56
- package/src/util/Store.js +174 -174
- package/src/util/defineElement.js +5 -5
- package/src/util/toString.js +5 -5
|
@@ -3,130 +3,118 @@
|
|
|
3
3
|
_element-js_ provides a simple way of Dependency Injection following the idea of the Context [Protocol Proposal](https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md).
|
|
4
4
|
|
|
5
5
|
#### Problem "Prop Drilling"
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
If Data has to be passed down the DOM Tree to descending Child Elements it is usually done by assigning data to the descendants attributes:
|
|
8
8
|
|
|
9
9
|
```js
|
|
10
10
|
export class PropDrilling extends TemplateElement {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
11
|
+
properties() {
|
|
12
|
+
return {
|
|
13
|
+
data: { some: 'data', which: 'bloats', the: 'attributes', in: 'DOM' }
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
template() {
|
|
18
|
+
return html`
|
|
19
|
+
<!-- child element uses the same exacte data-set as the parent does -->
|
|
20
|
+
<child-element redundant-data="${data}">
|
|
21
|
+
<!-- grand child component uses parts of the parents or even the root elements dataset -->
|
|
22
|
+
<grand-child-element in-data="${data.in}"></grand-child-element>
|
|
23
|
+
</child-element>
|
|
24
|
+
<!-- child component uses parts of the parents dataset -->
|
|
25
|
+
<another-child-element some-data="${data.some}" the-data="${data.the}"></another-child-element>
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
While this is possible and totally fine for primitive values it can get confusing very fast with a deep nesting and complex data structures.
|
|
32
|
-
|
|
31
|
+
While this is possible and totally fine for primitive values it can get confusing very fast with a deep nesting and complex data structures. It also bloats up the DOM Tree as redundant data ist being passed to multiple descending Elements being copied along the way.
|
|
32
|
+
|
|
33
|
+
#### Dependency Injection for the rescue
|
|
33
34
|
|
|
34
|
-
#### Dependency Injection for the rescue
|
|
35
|
-
|
|
36
35
|
To address the issues caused by "Prop Drilling" _element-js_ provides a simple Dependency Injection Implementation following the idea of the Context Protocol mentioned above.
|
|
37
36
|
|
|
38
37
|
##### Provide via provideProperties()
|
|
39
38
|
|
|
40
|
-
An Element can control whatever is to be "provided" to requesting Elements by implementing the provideProperties function provided by the `BaseElement`.
|
|
39
|
+
An Element can control whatever is to be "provided" to requesting Elements by implementing the provideProperties function provided by the `BaseElement`.
|
|
41
40
|
|
|
42
41
|
```js
|
|
43
|
-
|
|
44
42
|
export class AncestorElement extends TemplateElement {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
43
|
+
properties() {
|
|
44
|
+
return {
|
|
45
|
+
data: { some: 'data', which: 'bloats', the: 'attributes', in: 'DOM' }
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
provideProperties() {
|
|
49
|
+
return {
|
|
50
|
+
data: this.data,
|
|
51
|
+
in: this.data.in,
|
|
52
|
+
static: 'string'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
58
55
|
}
|
|
59
56
|
```
|
|
57
|
+
|
|
60
58
|
#### Vanilla JS Provide via Event Listener / Context Protocol
|
|
61
59
|
|
|
62
60
|
```html
|
|
63
61
|
<script>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
62
|
+
document.addEventListener('request-context', (event) => {
|
|
63
|
+
// global value
|
|
64
|
+
const vanillaValue = 'vanillaValue';
|
|
65
|
+
for (const [key, value] of Object.entries(event.detail)) {
|
|
66
|
+
if(key === 'vanillaContext') {
|
|
67
|
+
if (typeof value === 'function') {
|
|
68
|
+
// call function with context value
|
|
69
|
+
value(vanillaValue);
|
|
70
|
+
} else {
|
|
71
|
+
// assign as a property to Requestee
|
|
72
|
+
event.target[key] = vanillaValue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
79
77
|
</script>
|
|
80
78
|
```
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
|
|
84
80
|
##### Inject Properties via injectProperties()
|
|
85
81
|
|
|
86
|
-
An Element can define injection requests by implementing the injectProperties function provided by the `BaseElement`.
|
|
87
|
-
The initial values will also function as default values and will be replaced after the injection request is fulfilled by an Ancestor that provides a property with the requested name.
|
|
88
|
-
Injected properties will automatically become reactive properties within the elements scope. DEVs do not have to care about where the Value is actually coming from.
|
|
89
|
-
It will be just there at some Point after the Injection will trigger changes / updates just like regular [properties](./properties.md)..
|
|
82
|
+
An Element can define injection requests by implementing the injectProperties function provided by the `BaseElement`. The initial values will also function as default values and will be replaced after the injection request is fulfilled by an Ancestor that provides a property with the requested name. Injected properties will automatically become reactive properties within the elements scope. DEVs do not have to care about where the Value is actually coming from. It will be just there at some Point after the Injection will trigger changes / updates just like regular [properties](./properties.md)..
|
|
90
83
|
|
|
91
84
|
```js
|
|
92
85
|
export class DescendingElement extends TemplateElement {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
86
|
+
injectProperties() {
|
|
87
|
+
return {
|
|
88
|
+
in: '',
|
|
89
|
+
data: {},
|
|
90
|
+
static: '',
|
|
91
|
+
vanillaContext: ''
|
|
92
|
+
};
|
|
93
|
+
}
|
|
102
94
|
}
|
|
103
|
-
|
|
104
95
|
```
|
|
105
96
|
|
|
106
97
|
##### Request Context Values via manual context Request
|
|
107
98
|
|
|
108
|
-
If you want more control over what happens with an injected value after the Injection you can do a manual context Request by using the builtin requestContext function of the BaseElement.
|
|
99
|
+
If you want more control over what happens with an injected value after the Injection you can do a manual context Request by using the builtin requestContext function of the BaseElement.
|
|
100
|
+
|
|
109
101
|
```js
|
|
110
102
|
export class ManualRequestElement extends TemplateElement {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
103
|
+
properties() {
|
|
104
|
+
return {
|
|
105
|
+
reversedArray: []
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
connected() {
|
|
109
|
+
this.requestContext('regularArray', (injectedArray) => {
|
|
110
|
+
// do whatever you like with the value
|
|
111
|
+
const processedArray = injectedArray.reverse();
|
|
112
|
+
// OPTIONAL assign to a property to trigger an update and render the reversed values´
|
|
113
|
+
this.reversedArray = processedArray;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
124
116
|
}
|
|
125
117
|
```
|
|
126
118
|
|
|
127
|
-
Still looking for more Information ?
|
|
119
|
+
Still looking for more Information ?
|
|
128
120
|
You might take a look at the [Test Implementation](../../test/unit/context-protocol.test.html) which should cover all cases
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
@@ -117,7 +117,7 @@ export class ShadowElement extends TemplateElement {
|
|
|
117
117
|
|
|
118
118
|
By default, _element-js_ will only apply all style elements from the global document that are present in the initial HTML. It will not observe the document for any changes regarding style elements.
|
|
119
119
|
|
|
120
|
-
> Observing global styles is done via a MutationObserver on the whole document. This might impose performance issues.
|
|
120
|
+
> Observing global styles is done via a MutationObserver on the whole document. This might impose performance issues.
|
|
121
121
|
|
|
122
122
|
To enable global style observation you can add the following (inline, sync) script block to yor HTML.
|
|
123
123
|
|
package/docs/features/methods.md
CHANGED
|
@@ -1,33 +1,32 @@
|
|
|
1
|
-
|
|
2
1
|
### Methods
|
|
3
2
|
|
|
4
3
|
Besides public properties you can also shape the API for your element with public methods.
|
|
5
4
|
|
|
6
5
|
```javascript
|
|
7
|
-
import {BaseElement, defineElement} from '@webtides/element-js';
|
|
6
|
+
import { BaseElement, defineElement } from '@webtides/element-js';
|
|
8
7
|
|
|
9
8
|
export class ModalElement extends BaseElement {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
open() {
|
|
10
|
+
// do the things to actually open the modal…
|
|
11
|
+
}
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
defineElement('modal-element', ModalElement);
|
|
16
15
|
```
|
|
17
16
|
|
|
18
17
|
```javascript
|
|
19
|
-
import {BaseElement, defineElement} from '@webtides/element-js';
|
|
18
|
+
import { BaseElement, defineElement } from '@webtides/element-js';
|
|
20
19
|
|
|
21
20
|
export class OtherElement extends BaseElement {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
events() {
|
|
22
|
+
return {
|
|
23
|
+
this: {
|
|
24
|
+
click: () => {
|
|
25
|
+
this.$refs.modal.open();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
defineElement('other-element', OtherElement);
|
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
## Attributes/Properties
|
|
2
2
|
|
|
3
|
-
With attributes and properties you can build out and define the public API of an element. _element-js_ elements can have
|
|
4
|
-
three different types of properties.
|
|
3
|
+
With attributes and properties you can build out and define the public API of an element. _element-js_ elements can have three different types of properties.
|
|
5
4
|
|
|
6
5
|
```javascript
|
|
7
6
|
export class MyElement extends BaseElement {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
7
|
+
_privatePropery = 'I am private (by convention)';
|
|
8
|
+
publicProperty = 'I am public';
|
|
9
|
+
|
|
10
|
+
properties() {
|
|
11
|
+
return {
|
|
12
|
+
reactivePublicProperty: 'I am public & reactive'
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
log() {
|
|
17
|
+
console.log(this._privatePropery);
|
|
18
|
+
console.log(this.publicProperty);
|
|
19
|
+
console.log(this.reactivePublicProperty);
|
|
20
|
+
}
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
defineElement('my-element', MyElement);
|
|
@@ -26,31 +25,20 @@ defineElement('my-element', MyElement);
|
|
|
26
25
|
|
|
27
26
|
#### Defining properties in JavaScript
|
|
28
27
|
|
|
29
|
-
Public properties for JavaScript classes where recently added by the JavaScript standard committee. For more information
|
|
30
|
-
see
|
|
31
|
-
the [Class fields documentation on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_fields)
|
|
32
|
-
.
|
|
28
|
+
Public properties for JavaScript classes where recently added by the JavaScript standard committee. For more information see the [Class fields documentation on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_fields) .
|
|
33
29
|
|
|
34
|
-
On top of these fields _element-js_ adds another form of properties - reactive properties. By overwriting
|
|
35
|
-
the `properties()` method on your element and returning an object of key/value pairs you can define a list of reactive
|
|
36
|
-
public properties. Behind the scenes _element-js_ will automatically generate getters and setters for each property and
|
|
37
|
-
trigger an update/render for the element when these properties change.
|
|
30
|
+
On top of these fields _element-js_ adds another form of properties - reactive properties. By overwriting the `properties()` method on your element and returning an object of key/value pairs you can define a list of reactive public properties. Behind the scenes _element-js_ will automatically generate getters and setters for each property and trigger an update/render for the element when these properties change.
|
|
38
31
|
|
|
39
32
|
All types of properties can be accessed via the `this` operator within the element class or the template function.
|
|
40
33
|
|
|
41
34
|
#### Using attributes/properties in HTML
|
|
42
35
|
|
|
43
|
-
_element-js_ will merge all attributes with the reactive properties map. Values set via attribute will always take
|
|
44
|
-
precedence over values defined in the properties map. Attributes will still be defined as properties even when they are
|
|
45
|
-
not set in the properties map.
|
|
36
|
+
_element-js_ will merge all attributes with the reactive properties map. Values set via attribute will always take precedence over values defined in the properties map. Attributes will still be defined as properties even when they are not set in the properties map.
|
|
46
37
|
|
|
47
|
-
HTML only has the concept of attributes and `string` values. _element-js_ will automatically convert attributes to their
|
|
48
|
-
correct types of `string`, `number`, `boolean`, `array` and `object`.
|
|
38
|
+
HTML only has the concept of attributes and `string` values. _element-js_ will automatically convert attributes to their correct types of `string`, `number`, `boolean`, `array` and `object`.
|
|
49
39
|
|
|
50
|
-
> In JavaScript you will typically use camelCase for declaring properties. HTML attributes however only can be
|
|
51
|
-
> lowercase. _element-js_ will therefore convert dash-case names to camelCase variables and vice versa.
|
|
40
|
+
> In JavaScript you will typically use camelCase for declaring properties. HTML attributes however only can be lowercase. _element-js_ will therefore convert dash-case names to camelCase variables and vice versa.
|
|
52
41
|
|
|
53
42
|
#### Property options
|
|
54
43
|
|
|
55
|
-
Reactive properties can be fine-tuned further by providing options via the constructor. See `propertyOptions`
|
|
56
|
-
in [Constructor options](../concepts/classes.md).
|
|
44
|
+
Reactive properties can be fine-tuned further by providing options via the constructor. See `propertyOptions` in [Constructor options](../concepts/classes.md).
|
package/docs/features/refs.md
CHANGED
|
@@ -1,47 +1,39 @@
|
|
|
1
|
-
|
|
2
1
|
### Refs
|
|
3
2
|
|
|
4
|
-
To avoid constant lookups of (child) elements from your elements _element-js_ will collect all elements with
|
|
5
|
-
a `[ref=“id”]` attribute and make them available as an object on the element itself via the special `this.$refs`
|
|
6
|
-
reference.
|
|
7
|
-
_element-js_ also provides referencing a list of Nodes by adding a dangling `[]` to the refs id `[ref=“entries[]”]`.
|
|
8
|
-
Be aware that list references will override singular references with the same name as they are considered to be more
|
|
9
|
-
explicit.
|
|
3
|
+
To avoid constant lookups of (child) elements from your elements _element-js_ will collect all elements with a `[ref=“id”]` attribute and make them available as an object on the element itself via the special `this.$refs` reference. _element-js_ also provides referencing a list of Nodes by adding a dangling `[]` to the refs id `[ref=“entries[]”]`. Be aware that list references will override singular references with the same name as they are considered to be more explicit.
|
|
10
4
|
|
|
11
5
|
```html
|
|
12
|
-
|
|
13
6
|
<places-search>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
<input type="text" ref="input" />
|
|
8
|
+
<places-list ref="list">
|
|
9
|
+
<list-entry ref="entries[]">A</list-entry>
|
|
10
|
+
<list-entry ref="entries[]">B</list-entry>
|
|
11
|
+
<list-entry ref="entries[]">C</list-entry>
|
|
12
|
+
</places-list>
|
|
20
13
|
</places-search>
|
|
21
14
|
```
|
|
22
15
|
|
|
23
16
|
```javascript
|
|
24
|
-
import {BaseElement, defineElement, html} from '@webtides/element-js';
|
|
17
|
+
import { BaseElement, defineElement, html } from '@webtides/element-js';
|
|
25
18
|
|
|
26
19
|
export class PlacesSearch extends BaseElement {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
20
|
+
events() {
|
|
21
|
+
return {
|
|
22
|
+
input: {
|
|
23
|
+
blur: (e) => {
|
|
24
|
+
// fetch places...
|
|
25
|
+
const places = [];
|
|
26
|
+
// update singular ref
|
|
27
|
+
this.$refs.list = places;
|
|
28
|
+
// do something with a list reference
|
|
29
|
+
this.$refs.entries.forEach((entry) => console.log(entry.innerText)); // A , B , C
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
41
34
|
}
|
|
42
35
|
|
|
43
36
|
defineElement('places-search', PlacesSearch);
|
|
44
37
|
```
|
|
45
38
|
|
|
46
|
-
> _element-js_ will smartly add and remove all refs on every update/render cycle to ensure that they will always be
|
|
47
|
-
> correct even though you might have changed the child DOM tree during render cycles.
|
|
39
|
+
> _element-js_ will smartly add and remove all refs on every update/render cycle to ensure that they will always be correct even though you might have changed the child DOM tree during render cycles.
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
1
|
### Not Rendering Elements / BaseElement
|
|
3
2
|
|
|
4
|
-
More often than not you won't actually need to render anything from your element but rather only trigger some changes on
|
|
5
|
-
other elements, fire events or fetch data and distribute it to related elements.
|
|
3
|
+
More often than not you won't actually need to render anything from your element but rather only trigger some changes on other elements, fire events or fetch data and distribute it to related elements.
|
|
6
4
|
|
|
7
|
-
A good example for this pattern is to use container elements for fetching data and delegating it to child elements that
|
|
8
|
-
only take attributes/properties and simply render them.
|
|
5
|
+
A good example for this pattern is to use container elements for fetching data and delegating it to child elements that only take attributes/properties and simply render them.
|
|
9
6
|
|
|
10
7
|
```html
|
|
11
8
|
|
|
@@ -16,54 +13,51 @@ only take attributes/properties and simply render them.
|
|
|
16
13
|
```
|
|
17
14
|
|
|
18
15
|
```javascript
|
|
19
|
-
import {BaseElement, defineElement} from '@webtides/element-js';
|
|
16
|
+
import { BaseElement, defineElement } from '@webtides/element-js';
|
|
20
17
|
|
|
21
18
|
export class PlacesSearch extends BaseElement {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
19
|
+
events() {
|
|
20
|
+
return {
|
|
21
|
+
input: {
|
|
22
|
+
blur: (e) => {
|
|
23
|
+
// fetch places...
|
|
24
|
+
const places = ['list of place objects…'];
|
|
25
|
+
this.$refs.list = places;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
defineElement('places-search', PlacesSearch);
|
|
36
33
|
```
|
|
37
34
|
|
|
38
|
-
Another good use case for renderless elements is when you need to change some classes or styles on child elements. It is
|
|
39
|
-
a bit like `jQuery` but much better because everything is declaratively composed of little elements instead of having a
|
|
40
|
-
big JavaScript file full of little mutations.
|
|
35
|
+
Another good use case for renderless elements is when you need to change some classes or styles on child elements. It is a bit like `jQuery` but much better because everything is declaratively composed of little elements instead of having a big JavaScript file full of little mutations.
|
|
41
36
|
|
|
42
37
|
```html
|
|
43
|
-
|
|
44
38
|
<dropdown-element>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
<button>Options</button>
|
|
40
|
+
<ul ref="“list”" class="“”hidden">
|
|
41
|
+
<li>Profile</li>
|
|
42
|
+
<li>Settings</li>
|
|
43
|
+
<li>Sign out</li>
|
|
44
|
+
</ul>
|
|
51
45
|
</dropdown-element>
|
|
52
46
|
```
|
|
53
47
|
|
|
54
48
|
```javascript
|
|
55
|
-
import {BaseElement, defineElement} from '@webtides/element-js';
|
|
49
|
+
import { BaseElement, defineElement } from '@webtides/element-js';
|
|
56
50
|
|
|
57
51
|
class DropdownElement extends BaseElement {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
events() {
|
|
53
|
+
return {
|
|
54
|
+
button: {
|
|
55
|
+
click: () => {
|
|
56
|
+
this.$refs.list.classList.remove('hidden');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
67
61
|
}
|
|
68
62
|
|
|
69
63
|
defineElement('dropdown-element', DropdownElement);
|