import { css, html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { tailwind } from '../styles/tailwind.js'; /** * A counter button — small on purpose, but it demonstrates the four things * almost every Lit component needs: a reactive property, scoped styles, a * custom event, and a slot. * * @fires count-changed - Dispatched when the count changes. `detail.count` * carries the new value. * @slot - Label rendered inside the button. * @csspart button - The underlying button element, styleable from outside. */ @customElement('counter-button') export class CounterButton extends LitElement { /** * Tailwind first, then the rules utilities cannot express. Later sheets win, * so the handwritten block stays last. */ static override styles = [ tailwind, css` /* The host element itself, which no utility class can target. */ :host { display: inline-block; } button { /* * Form controls do not inherit the page font. Tailwind's preflight * normally fixes that, but preflight is document-level and is not * adopted into shadow roots, so components repeat the one line here. */ font: inherit; } `, ]; /** * Current count. Declared with `@property` (not `@state`) so it is part of * the public API and can be set from markup as `count="3"`. */ @property({ type: Number, reflect: true }) count = 0; /** How much each click adds. */ @property({ type: Number, attribute: 'step-by' }) stepBy = 1; override render() { return html` `; } // Private class field syntax keeps the method off the public API surface. #increment = (): void => { this.count += this.stepBy; // `composed: true` is required for the event to escape the shadow root. this.dispatchEvent( new CustomEvent<{ count: number }>('count-changed', { detail: { count: this.count }, bubbles: true, composed: true, }), ); }; } declare global { interface HTMLElementTagNameMap { 'counter-button': CounterButton; } }