Skip to content

Commit

Permalink
[article] Create a lit cheat sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
e111077 committed Nov 26, 2024
1 parent 42d1ed5 commit e028ae4
Show file tree
Hide file tree
Showing 157 changed files with 3,399 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { html, LitElement, css } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
render() {
return html`<p>I'm blue</p><div>I'm red</div>`;
}

static styles = css`
p {
color: blue;
}
div {
color: red;
}
`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "100px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { html as staticHTML, StaticValue } from 'lit/static-html.js';
import { live } from 'lit/directives/live.js';

@customElement('input-or-textfield')
export class MyElement extends LitElement {
// attribute is false because this is a value that can't be serialized to an
// HTML attribute
@property({ attribute: false }) tagLiteral: StaticValue|null = null;
@property() value = '';

render() {
return html`
${
// NOTE: the live() directive prevents setting the .value property if
// the live value of the input / textfield already matches this.value.
// This is important since static html templates should not be thrashed
// due to performance concerns.
staticHTML`
<${this.tagLiteral}
@input=${this.#onInput}
.value=${live(this.value)}></${this.tagLiteral}>
`
}
<div>
The value of the input is: ${this.value}
</div>
`;
}

#onInput(e: InputEvent) {
this.value = (e.target as (HTMLInputElement | HTMLTextAreaElement)).value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { css, html, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { literal } from 'lit/static-html.js';
import './input-or-textfield.js';

@customElement('my-element')
export class MyElement extends LitElement {
@state() tagLiteral = literal`input`;
render() {
return html`
<!-- /* playground-fold */ -->
<fieldset>
<legend>Choose a tag to render:</legend>
<div>
<label>
<input
type="radio"
name="selection"
@change=${this.#onChange}
value="input"
checked>
input
</label>
</div>
<div>
<label>
<input
type="radio"
name="selection"
@change=${this.#onChange}
value="textarea">
textarea
</label>
</div>
</fieldset>
<!-- /* playground-fold-end */ -->
<input-or-textfield
value="this is the default value"
.tagLiteral=${this.tagLiteral}>
</input-or-textfield>
`;
}

#onChange(e: InputEvent) {
const target = e.target as HTMLInputElement;
this.tagLiteral = target.value === 'input' ? literal`input` : literal`textarea`;
}

static styles = css`/* playground-fold */:host { font-family: sans-serif; } :host > * { margin-block: .5em; }/* playground-fold-end */`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "/samples/v3-base.json",
"files": {
"input-or-textfield.ts": {},
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "175px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { html, LitElement, css } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';

@customElement('my-element')
export class MyElement extends LitElement {
@state() counter = 0

firstUpdated() {
setInterval(() => this.counter += 1 , 1000);
}

render() {
const classes = {
red: this.counter % 2 === 0,
blue: this.counter % 2 === 1
};
return html`<p class=${classMap(classes)}>Hello!</p>`;
}

static styles = css`
.red {
color: red;
}
.blue {
color: blue;
}
`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "100px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { html, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
@state() private someBoolean = false;

render() {
let someText = html`<p>Some text</p>`;

if (this.someBoolean) {
someText = html`<p>Some other text</p>`;
}

return html`
<button
@click=${() => {this.someBoolean = !this.someBoolean}}>
Toggle template
</button>
<div>This is an inline ternary conditional</div>
${this.someBoolean ? html`<p>Some other text</p>` : html`<p>Some text</p>`}
<div>This is a variable conditional</div>
${someText}
`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "200px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import { trustedStyles, type CSSStyleSheet } from './trusted-stringified-css-source.js';

// Use constructable stylesheets on TRUSTED CSS strings to use them in a LitElement
const styles = new CSSStyleSheet();
// this type assertion is needed for the older version of TS like that the lit.dev website uses
(styles as unknown as CSSStyleSheet).replace(trustedStyles);

@customElement('my-element')
export class MyElement extends LitElement {
static styles = styles;
render() {
return html`
<div>
This should be red!
</div>
`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"trusted-stringified-css-source.ts": {},
"index.html": {}
},
"previewHeight": "100px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const trustedStyles = `
div {
color: red;
}
`;

// This may be needed for some older versions of TS
export type CSSStyleSheet = typeof globalThis['CSSStyleSheet'] & {
replaceSync(cssText: string): void;
replace(cssText: string): void;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script type="module" src="./my-element.js"></script>
<style>
.styled my-element::part(paragraph) {
color: yellow;
border-color: white;
padding: 8px;
margin: 2px;
}

.styled {
background-color: black;
}

div {
padding: 4px;
}
</style>

<div class="styled">
<my-element></my-element>
</div>
<div>
<my-element></my-element>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { html, LitElement, css } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
static styles = css`
p {
color: blue;
border: 1px solid black;
padding: 4px;
margin-block: 4px;
}
`;

render() {
return html`<p part="paragraph">This is in a shadow root!</p>`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "120px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element array='1,"2",3,4,"5"'></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { html, LitElement } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';import {ComplexAttributeConverter} from 'lit';

/**
* Bidirectionally converts an array from an attribute to a property of the
* following format:
*
* array-attribute='1, "2", 3' to [1, '2', 3]
*/
export const arrayConverter: ComplexAttributeConverter<Array<unknown>> = {
toAttribute: (array: Array<unknown>) => {
return JSON.stringify(array).substring(1, JSON.stringify(array).length - 1);
},
fromAttribute: (value: string) => {
try {
return JSON.parse(`[${value}]`);
} catch {
return [];
}
}
};

@customElement('my-element')
export class MyElement extends LitElement {
@property({ converter: arrayConverter, reflect: true })
array: Array<number|string> = [];

render() {
return this.array.map((item) =>
html`<div>${typeof item}: ${item}</div>`
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "200px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';

export type ScoreEvent = CustomEvent<number>;

@customElement('game-player')
export class GamePlayer extends LitElement {
render() {
return html`
<button @click=${() => this.handleScore(7)}>Touchdown!</button>
<button @click=${() => this.handleScore(3)}>Field goal!</button>
`;
}

handleScore(points: number) {
this.dispatchEvent(new CustomEvent('score', { detail: points, bubbles: true }));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./score-board.js"></script>

<score-board></score-board>
Loading

0 comments on commit e028ae4

Please sign in to comment.