# MATES

**MATES** is a TypeScript-first front-end framework built on lit-html — no virtual DOM, no compiler needed. It's faster than React, fully type-safe, and runs via Vite, Bun, or CDN (~45KB gzipped).

Its architecture follows the MATES pattern: Mutable State, Actions, Templates, Events, and Setups.

It comes fully batteries-included with: a Router, state management, date/timezone utils, fetch & WebSocket utils, animations, form validation, CSS-in-JS, portals, tooltips, popups, UUID generation, memoisation, cancellable promises, pagination, lazy loading, local storage sync across tabs, a Task Manager, and a rich set of built-in hooks — eliminating the need for most third-party libraries. List/table virtualisation is in the separate [`mates-virtual`](./mates-virtual) package.

---

## Why Mates?

Most frameworks ask you to learn a new mental model — JSX compilers, reactive transforms, or a shadow DOM abstraction. Mates takes a different approach:

- **No compiler, no JSX** — just tagged template literals from `lit-html`. Works in any TypeScript project out of the box.
- **No virtual DOM** — `lit-html` patches only the parts of the DOM that actually changed. Updates are surgical, not diffed from scratch.]
- **Predictable two-layer components** — the outer function (setup) runs once. The inner function (render) runs on every update. Clear separation between initialization and rendering.
- **Batteries included** — routing, async state machines, CSS-in-JS, WebSocket, portals, and animations are all first-party and designed to work together. Virtualization is in `mates-virtual`.

---

## Installation

```bash
npm install mates
```

Mates requires `lit-html` as a peer dependency (automatically installed):

```bash
npm install mates lit-html
```

---

## Quick Start

```typescript
import { atom, html, renderX, x } from "mates";

// A simple counter component
const Counter = () => {
  const count = atom(0);

  return () => html`
    <button @click=${() => count.set((n) => n - 1)}>−</button>
    <span>${count()}</span>
    <button @click=${() => count.set((n) => n + 1)}>+</button>
  `;
};

// Mount to the DOM
renderX(Counter, document.getElementById("app")!);
```

---

## Components

### The Two-Layer Model

Every Mates component is a **closure** with two layers:

| Layer | Runs | Purpose |
|-------|------|---------|
| **Outer function** | Once on mount | Create atoms, set up subscriptions using **on** function, register lifecycle hooks..etc |
| **Inner function** | Every render | Read reactive values and return a `TemplateResult` |

```typescript
import { atom, html } from "mates";
import type { Props } from "mates";

const Counter = (propsFn: Props<{ label: string }>) => {
  // ── Outer: runs once ────────────────────────────────────
  const count = atom(0);

  // ── Inner: runs on every re-render ──────────────────────
  return () => html`
    <p>${propsFn().label}: ${count()}</p>
    <button @click=${() => count.set((n) => n + 1)}>Increment</button>
  `;
};
```

> **Rule of thumb:** atoms, effects, hooks, and subscriptions always go in the **outer** function, you can also make api calls..etc you can be assured that this code is only executed once. template function always returns html temlate strings. Modern IDEs have a built in formatting support for the html template strings.

---

### Rendering Components

Use `x()` (also exported as `view`) to embed a component inside a template. Use `renderX()` to mount a component into a real DOM element.

**x** function lets you mount components in another component. you can also use **view** for the same puprose. **x** takes in a component.

```typescript
import { html, renderX, x } from "mates";

// Embed in another component's template
const App = () => () => html`
  <main>
    <h1>My App</h1>
    ${x(Counter, { label: "Clicks" })}
  </main>
`;

```

---


## IDE Support

Install the **Lit** extension for VS Code / Cursor ([marketplace](https://marketplace.visualstudio.com/items?itemName=lit.lit-plugin)) to get:

- Syntax highlighting inside `html\`...\`` template literals
- Attribute and property completions on HTML elements
- Inline TypeScript errors in templates

---

## License

MIT