CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-riot

Simple and elegant component-based UI library

Pending
Overview
Eval results
Files

component-factory.mddocs/

Component Factory

Direct component creation without global registration, useful for dynamic components and programmatic component instantiation. This approach bypasses the global registry system.

Capabilities

Component Factory Function

Creates a component instance factory from a component wrapper without registering it globally.

/**
 * Helper method to create component without relying on registered components
 * @param wrapper - Component implementation wrapper
 * @returns Function that creates and mounts component instances
 */
function component<Props extends DefaultProps, State extends DefaultState, Component extends RiotComponent>(
  wrapper: RiotComponentWrapper<Component>
): (
  el: HTMLElement,
  initialProps?: Props,
  meta?: ComponentMeta
) => Component;

Usage Example:

import { component } from "riot";

// Define component without registration
const createTimer = component({
  css: "timer { display: block; color: blue; }",
  template: (template, expressionTypes, bindingTypes) => 
    template("<p>Time: { state.seconds }s</p>", [
      // Template bindings
    ]),
  exports: {
    onBeforeMount(props) {
      this.state = { seconds: props.start || 0 };
      this.interval = setInterval(() => {
        this.update({ seconds: this.state.seconds + 1 });
      }, 1000);
    },
    onUnmounted() {
      clearInterval(this.interval);
    }
  }
});

// Create and mount component instance
const element = document.getElementById("timer-container");
const timerComponent = createTimer(element, { start: 10 });

Component Factory with Metadata

The factory function accepts optional metadata for advanced component features:

interface ComponentMeta {
  /** Slot data for child content */
  slots?: TagSlotData[];
  
  /** Attribute expression bindings */
  attributes?: AttributeExpressionData[];
  
  /** Parent scope for nested components */
  parentScope?: any;
}

Usage Example:

// Create component with slots and attributes
const element = document.getElementById("container");
const meta = {
  slots: [
    {
      id: "header",
      html: "<h2>Dynamic Header</h2>",
      bindings: []
    }
  ],
  attributes: [
    {
      name: "data-theme",
      evaluate: () => "dark"
    }
  ]
};

const componentInstance = createMyComponent(element, { title: "Hello" }, meta);

Enhanced Component Factory (riot+compiler)

The riot+compiler build provides an enhanced component factory that automatically handles runtime slot creation:

/**
 * Enhanced component factory that creates slots from DOM content
 * @param wrapper - Component implementation wrapper
 * @returns Enhanced factory function with automatic slot handling
 */
function component(wrapper: RiotComponentWrapper): (
  el: HTMLElement,
  props?: any,
  meta?: ComponentMeta
) => RiotComponent;

Usage Example:

import { component } from "riot+compiler";

const createWidget = component({
  template: (template, expressionTypes, bindingTypes) => 
    template(`
      <div class="widget">
        <slot name="content"></slot>
      </div>
    `, [
      // Slot bindings are automatically handled
    ]),
  exports: {
    onMounted() {
      console.log("Widget mounted with slots:", this.slots);
    }
  }
});

// HTML content becomes slots automatically
const element = document.querySelector(".widget-container");
// Any existing content in element becomes slot content
const widget = createWidget(element, { theme: "modern" });

Dynamic Component Creation

Component factories are particularly useful for dynamic component creation:

import { component } from "riot";

// Factory for creating different card types
function createCardComponent(cardType) {
  return component({
    css: `.card-${cardType} { border: 2px solid ${getCardColor(cardType)}; }`,
    template: (template) => template(`
      <div class="card-${cardType}">
        <h3>{ props.title }</h3>
        <p>{ props.content }</p>
      </div>
    `),
    exports: {
      onMounted() {
        console.log(`${cardType} card mounted`);
      }
    }
  });
}

// Create different card types dynamically
const createInfoCard = createCardComponent("info");
const createWarningCard = createCardComponent("warning");

// Use the factories
const infoCard = createInfoCard(document.getElementById("info"), {
  title: "Information",
  content: "This is an info card"
});

const warningCard = createWarningCard(document.getElementById("warning"), {
  title: "Warning",
  content: "This is a warning card"
});

Types

interface ComponentMeta {
  slots?: TagSlotData[];
  attributes?: AttributeExpressionData[];
  parentScope?: any;
}

type TagSlotData = {
  id: string;
  html: string;
  bindings: BindingData[];
};

type AttributeExpressionData = {
  name: string;
  evaluate: () => any;
};

type BindingData = {
  selector: string;
  type: number;
  evaluate: () => any;
};

Install with Tessl CLI

npx tessl i tessl/npm-riot

docs

compilation.md

component-factory.md

component-registration.md

index.md

mounting-lifecycle.md

plugin-system.md

pure-components.md

utilities.md

tile.json