CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-lit--task

A controller for Lit that renders asynchronous tasks.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

status-rendering.mddocs/

Status and Rendering

Task status tracking and template rendering functionality for displaying different task states with appropriate UI feedback.

Capabilities

Task Status Constants

Enumeration of task execution states.

/**
 * Constants representing different task execution states
 */
const TaskStatus = {
  /** Task has not been executed yet */
  INITIAL: 0,
  /** Task is currently running */
  PENDING: 1,
  /** Task completed successfully */
  COMPLETE: 2,
  /** Task failed with an error */
  ERROR: 3,
} as const;

/**
 * Type representing any valid task status value
 */
type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus];

Usage Examples:

import { Task, TaskStatus } from "@lit/task";

class MyElement extends LitElement {
  private _task = new Task(this, {
    task: async () => fetchData(),
    args: () => []
  });

  render() {
    // Check status directly
    if (this._task.status === TaskStatus.PENDING) {
      return html`<p>Loading...</p>`;
    }
    
    if (this._task.status === TaskStatus.ERROR) {
      return html`<p>Error: ${this._task.error}</p>`;
    }
    
    return html`<p>Data: ${this._task.value}</p>`;
  }
}

Status-Based Rendering

Template rendering method that provides different outputs based on task state.

/**
 * Render different templates based on current task status
 * @param renderer - Object with optional methods for each status
 * @returns Result from the appropriate renderer method
 */
render<T extends StatusRenderer<R>>(renderer: T): MaybeReturnType<T>;

/**
 * Object defining rendering functions for different task states
 */
interface StatusRenderer<R> {
  /** Template for INITIAL state (task not yet run) */
  initial?: () => unknown;
  /** Template for PENDING state (task currently running) */
  pending?: () => unknown;
  /** Template for COMPLETE state (task succeeded) */
  complete?: (value: R) => unknown;
  /** Template for ERROR state (task failed) */
  error?: (error: unknown) => unknown;
}

Usage Examples:

import { LitElement, html } from "lit";
import { Task } from "@lit/task";

class DataComponent extends LitElement {
  private _dataTask = new Task(this, {
    task: async ([id]) => {
      const response = await fetch(`/api/data/${id}`);
      if (!response.ok) throw new Error('Failed to load');
      return response.json();
    },
    args: () => [this.dataId]
  });

  render() {
    return html`
      <div class="data-container">
        ${this._dataTask.render({
          initial: () => html`<p>Ready to load data</p>`,
          pending: () => html`
            <div class="spinner"></div>
            <p>Loading data...</p>
          `,
          complete: (data) => html`
            <h3>${data.title}</h3>
            <p>${data.description}</p>
            <ul>
              ${data.items.map(item => html`<li>${item}</li>`)}
            </ul>
          `,
          error: (error) => html`
            <div class="error">
              <p>Failed to load data: ${error.message}</p>
              <button @click=${() => this._dataTask.run()}>
                Retry
              </button>
            </div>
          `
        })}
      </div>
    `;
  }
}

Advanced Rendering Patterns

More sophisticated rendering approaches using task status and values.

Conditional Rendering:

class AdvancedComponent extends LitElement {
  private _userTask = new Task(this, {
    task: async ([userId]) => getUserData(userId),
    args: () => [this.userId]
  });

  render() {
    // Combine status checking with render method
    const userContent = this._userTask.render({
      pending: () => html`<loading-spinner></loading-spinner>`,
      complete: (user) => html`
        <user-card 
          .name=${user.name}
          .email=${user.email}
          .avatar=${user.avatar}
        ></user-card>
      `,
      error: () => html`<error-message message="User not found"></error-message>`
    });

    return html`
      <div class="user-section">
        <h2>User Profile</h2>
        ${userContent}
        ${this._userTask.status === TaskStatus.COMPLETE ? html`
          <button @click=${this._handleEdit}>Edit Profile</button>
        ` : ''}
      </div>
    `;
  }
}

Nested Task Rendering:

class NestedTaskComponent extends LitElement {
  private _categoriesTask = new Task(this, {
    task: async () => getCategories(),
    args: () => []
  });

  private _itemsTask = new Task(this, {
    task: async ([categoryId]) => getItemsByCategory(categoryId),
    args: () => [this.selectedCategory]
  });

  render() {
    return html`
      <div class="catalog">
        <nav>
          ${this._categoriesTask.render({
            pending: () => html`<p>Loading categories...</p>`,
            complete: (categories) => html`
              ${categories.map(cat => html`
                <button 
                  @click=${() => this.selectedCategory = cat.id}
                  ?selected=${this.selectedCategory === cat.id}
                >
                  ${cat.name}
                </button>
              `)}
            `
          })}
        </nav>
        
        <main>
          ${this._itemsTask.render({
            initial: () => html`<p>Select a category to view items</p>`,
            pending: () => html`<p>Loading items...</p>`,
            complete: (items) => html`
              <div class="items-grid">
                ${items.map(item => html`
                  <item-card .item=${item}></item-card>
                `)}
              </div>
            `,
            error: () => html`<p>Failed to load items</p>`
          })}
        </main>
      </div>
    `;
  }
}

docs

argument-equality.md

index.md

status-rendering.md

task-management.md

tile.json