Skip to content

Commit cf5f9c1

Browse files
committed
add properties and state examples
1 parent 5cc518a commit cf5f9c1

File tree

15 files changed

+351
-1
lines changed

15 files changed

+351
-1
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<script type="module" src="./my-element.js"></script>
2+
3+
<my-element array='1,"2",3,4,"5"'></my-element>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { html, LitElement } from 'lit';
2+
import { customElement, property, state } from 'lit/decorators.js';import {ComplexAttributeConverter} from 'lit';
3+
4+
/**
5+
* Bidirectionally converts an array from an attribute to a property of the
6+
* following format:
7+
*
8+
* array-attribute='1, "2", 3' to [1, '2', 3]
9+
*/
10+
export const arrayConverter: ComplexAttributeConverter<Array<unknown>> = {
11+
toAttribute: (array: Array<unknown>) => {
12+
return JSON.stringify(array).substring(1, JSON.stringify(array).length - 1);
13+
},
14+
fromAttribute: (value: string) => {
15+
try {
16+
return JSON.parse(`[${value}]`);
17+
} catch {
18+
return [];
19+
}
20+
}
21+
};
22+
23+
@customElement('my-element')
24+
export class MyElement extends LitElement {
25+
@property({ converter: arrayConverter, reflect: true })
26+
array: Array<number|string> = [];
27+
28+
render() {
29+
return this.array.map((item) =>
30+
html`<div>${typeof item}: ${item}</div>`
31+
);
32+
}
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "/samples/v3-base.json",
3+
"files": {
4+
"my-element.ts": {},
5+
"index.html": {}
6+
},
7+
"previewHeight": "200px"
8+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { html, LitElement } from 'lit';
2+
import { customElement, property } from 'lit/decorators.js';
3+
4+
@customElement('id-card')
5+
export class IdCard extends LitElement {
6+
// Default attribute converter is string
7+
@property() name = '';
8+
// Number attribute converter converts attribtues to numbers
9+
@property({ type: Number }) age = 0;
10+
// Boolean attribute converter converts attribtues to boolean using
11+
// .hasAttribute(). NOTE: boolean-attribute="false" will result in `true`
12+
@property({ type: Boolean }) programmer = false;
13+
// You can also specify the attribute name
14+
@property({ type: Boolean, attribute: 'is-cool' }) isCool = false;
15+
16+
render() {
17+
return html`
18+
<h3>${this.name}</h3>
19+
<p>Age: ${this.age}</p>
20+
<label style="display: block;">
21+
<input disabled type="checkbox" ?checked=${this.programmer}>
22+
Programmer
23+
</label>
24+
<label>
25+
<input disabled type="checkbox" ?checked=${this.isCool}>
26+
Is Cool
27+
</label>
28+
`;
29+
}
30+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<script type="module" src="./my-wallet.js"></script>
2+
3+
<my-wallet></my-wallet>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { html, LitElement } from 'lit';
2+
import { customElement } from 'lit/decorators.js';
3+
import './id-card.js';
4+
5+
@customElement('my-wallet')
6+
export class MyWallet extends LitElement {
7+
render() {
8+
return html`
9+
<id-card .name=${"Steven"} .age=${27} ?programmer=${true} .isCool=${true}></id-card>
10+
<!-- It can also convert attributes into properties -->
11+
<id-card name="Elliott" age="30" programmer></id-card>
12+
<!--
13+
NOTE: boolean-attribute="false" will be true, because the default
14+
boolean attribute converter uses .hasAttribute()
15+
-->
16+
<id-card name="Dan" age="35" programmer is-cool></id-card>
17+
`;
18+
}
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "/samples/v3-base.json",
3+
"files": {
4+
"id-card.ts": {},
5+
"my-wallet.ts": {},
6+
"index.html": {}
7+
},
8+
"previewHeight": "400px"
9+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<script type="module" src="./my-element.js"></script>
2+
3+
<my-element></my-element>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { html, LitElement } from 'lit';
2+
import { customElement, state } from 'lit/decorators.js';
3+
4+
@customElement('my-element')
5+
export class MyElement extends LitElement {
6+
// Duration affects render, so it should be reactive. Though we don't want it
7+
// to be exposed to consumers of my-element because we only want to expose
8+
// `start()`, `pause()`, `reset()`, so we use a private state.
9+
@state() private _duration = 0;
10+
// isPlaying affects render, so it should be reactive. Though we don't want it
11+
// to be exposed to consumers of my-element, so we use a private state.
12+
@state() private _isPlaying = false;
13+
private lastTick = 0;
14+
15+
render() {
16+
const min = Math.floor(this._duration / 60000);
17+
const sec = pad(min, Math.floor(this._duration / 1000 % 60));
18+
const hun = pad(true, Math.floor(this._duration % 1000 / 10));
19+
20+
return html`
21+
<div>
22+
${min ? `${min}:${sec}.${hun}` : `${sec}.${hun}`}
23+
</div>
24+
<div>
25+
${this._isPlaying ?
26+
html`<button @click=${this.pause}>Pause</button>` :
27+
html`<button @click=${this.start}>Play</button>`
28+
}
29+
<button @click=${this.reset}>Reset</button>
30+
</div>
31+
`;
32+
}
33+
34+
start() {
35+
this._isPlaying = true;
36+
this.lastTick = Date.now();
37+
this._tick();
38+
}
39+
40+
pause() {
41+
this._isPlaying = false;
42+
}
43+
44+
reset() {
45+
this._duration = 0;
46+
}
47+
48+
private _tick() {
49+
if (this._isPlaying) {
50+
const now = Date.now();
51+
this._duration += Math.max(0, now - this.lastTick);
52+
this.lastTick = now;
53+
requestAnimationFrame(() => this._tick());
54+
}
55+
}
56+
57+
connectedCallback() {
58+
super.connectedCallback();
59+
this.reset();
60+
}
61+
}
62+
/* playground-fold */
63+
function pad(pad: unknown, val: number) {
64+
return pad ? String(val).padStart(2, '0') : val;
65+
}
66+
/* playground-fold-end */
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "/samples/v3-base.json",
3+
"files": {
4+
"my-element.ts": {},
5+
"index.html": {}
6+
},
7+
"previewHeight": "100px"
8+
}

0 commit comments

Comments
 (0)