Tiny·Engine (Core)

Concepts

Capsules

A capsule is the smallest unit of behaviour in tiny-engine. It owns one DOM element, refs, props, events, and cleanup.

The two forms

Every capsule can be written either as a class extending Capsule or as a plain function. They share the same core primitives; use whichever form reads better in your codebase.

Class form

tabs.ts
import { Capsule } from "tiny-engine-core";

class Tabs extends Capsule {
  static defaults = {
    activeIndex: 0,
  };

  constructor(el, options) {
    super(el, options);

    this.onPropChange("activeIndex", (next, previous) => {
      console.log("tab changed", previous, next);
    });

    this.on(this.el, "click", (event) => {
      const tab = event.target.closest("[data-tab]");
      if (tab) this.props.activeIndex = Number(tab.dataset.tab);
    });
  }
}

Functional form

tabs-fn.ts
UI.register("tabs", (el, api) => {
  function setActive(index) {
    api.props.activeIndex = index;
    api.refs.panel.textContent = `Active tab: ${index}`;
  }

  api.on(el, "click", (event) => {
    const tab = event.target.closest("[data-tab]");
    if (tab) setActive(Number(tab.dataset.tab));
  });

  return {
    setActive,
    syncOptions(nextOptions) {
      setActive(Number(nextOptions.activeIndex ?? 0));
    },
  };
});

Refs

Any root or descendant with a ref attribute is collected into refs. Ref lookup is lazy, so newly inserted refs can be found after refresh() or observer updates.

<div ui-gallery>
  <button ref="prev">Previous</button>
  <ul ref="track">
    <li>A</li>
    <li>B</li>
  </ul>
  <button ref="next">Next</button>
</div>

this.refs.prev   // HTMLButtonElement
this.refs.next   // HTMLButtonElement
this.refs.track  // HTMLUListElement

Props and options

The marker attribute can hold JSON options, and {prefix}-{name}-* attributes become camelCased props. Values are parsed as booleans, numbers, JSON, or strings.

<div
  ui-tabs
  ui-tabs-active-index="2"
  ui-tabs-options='{"orientation":"vertical"}'
>
  <div ref="panel"></div>
</div>

becomes:

this.props.activeIndex === 2;
this.props.options.orientation === "vertical";