import { Meta } from '@storybook/addon-docs/blocks';

<Meta title="Docs/Frameworks/HTML" />

# HTML

The kit ships as standard **custom elements** (`kc-*` tags) — no framework required. Import the
bundle once as a side-effect and every element is registered globally, ready to drop into any HTML
page or templating system.

There are **two ways to build with the kit**, and you can mix them:

1. **`<kc-chat>`** — the batteries-included shell: a whole chat experience in one tag. Fastest start.
2. **Compose the individual elements** (`<kc-conversations>`, `<kc-markdown>`, `<kc-artifact>`, …)
   into your own layout when you want full control.

Both are shown below.

## Install & setup

```bash
npm i @kitn.ai/chat
```

Register the custom elements once (a side-effect import), then use the tags anywhere in your HTML:

```js
// Once, near your app entry — registers all <kc-*> elements globally.
import '@kitn.ai/chat/elements';
```

- No CSS to import: each element is styled inside its own Shadow DOM. Only pull in
  `@kitn.ai/chat/theme.css` if you want to override design tokens (see **Theming**).

### No-build / CDN option

No bundler? Load the module directly from a CDN and you're done:

```html
<script type="module">
  import 'https://cdn.jsdelivr.net/npm/@kitn.ai/chat/dist/kitn-chat.es.js';
</script>
```

Every `<kc-*>` element is then available as a global custom element — no install, no build step.

## Quick start — the all-in-one shell

`<kc-chat>` is **transport-agnostic**: give it a `messages` array, handle the `submit` event, and
stream your model's reply back into the property. You own the request; the element owns the UI.

```html
<!DOCTYPE html>
<html>
<head>
  <!-- optional: only needed to override design tokens -->
  <link rel="stylesheet" href="./node_modules/@kitn.ai/chat/theme.css" />
  <style>
    html, body { margin: 0; height: 100%; }
    .app { display: flex; flex-direction: column; height: 100dvh; }
  </style>
</head>
<body>
  <!-- Put the element in a flex parent and give it flex: 1.
       The elements are display:block and fill their box. -->
  <div class="app">
    <kc-chat id="chat" style="flex: 1; min-height: 0;"></kc-chat>
  </div>

  <script type="module">
    import '@kitn.ai/chat/elements';

    const chat = document.getElementById('chat');

    // Arrays and objects → JS properties (never attributes)
    chat.messages = [
      { id: '1', role: 'assistant', content: 'Hello! How can I help?', actions: ['copy', 'like', 'dislike'] },
    ];
    chat.suggestions = ['Summarize the chat', 'Start fresh'];

    // Interactions → addEventListener (CustomEvents, they don't bubble)
    chat.addEventListener('kc-submit', async (e) => {
      const text = e.detail.value;

      // Append user message — always assign a NEW array to trigger a re-render
      const history = [...chat.messages, { id: crypto.randomUUID(), role: 'user', content: text }];
      chat.messages = history;
      chat.loading = true;

      // Stream into an empty assistant placeholder
      const aid = crypto.randomUUID();
      chat.messages = [...history, { id: aid, role: 'assistant', content: '' }];

      let answer = '';
      for await (const token of streamFromYourAPI(history)) {
        answer += token;
        // Replace the placeholder with a new object each chunk
        chat.messages = chat.messages.map((m) =>
          m.id === aid ? { ...m, content: answer } : m
        );
      }
      chat.loading = false;
    });
  </script>
</body>
</html>
```

> **Reactivity:** always assign a **new array** (and a new object for any message you change).
> Mutating an existing object in place will not trigger a re-render.

## Go further — compose the pieces

`<kc-chat>` is one option, not the only one. Every element can be placed independently, so you can
assemble your own layout. Here's a multi-conversation shell — a `<kc-conversations>` sidebar next
to the `<kc-chat>` thread:

```html
<style>
  html, body { margin: 0; height: 100%; }
  .workspace { display: flex; height: 100dvh; }
</style>

<div class="workspace">
  <kc-conversations id="sidebar" style="width: 300px; flex-shrink: 0;"></kc-conversations>
  <kc-chat id="chat" style="flex: 1; min-width: 0;"></kc-chat>
</div>

<script type="module">
  import '@kitn.ai/chat/elements';

  const sidebar = document.getElementById('sidebar');
  const chat = document.getElementById('chat');

  // Rich data → JS properties
  sidebar.conversations = myConversations;
  chat.messages = loadMessages(myConversations[0]?.id);

  sidebar.addEventListener('kc-conversation-select', (e) => {
    chat.messages = loadMessages(e.detail.id);
  });

  sidebar.addEventListener('kc-new-chat', () => startNewConversation());

  chat.addEventListener('kc-submit', (e) => sendMessage(e.detail.value));
</script>
```

### Make the panels resizable

Want a draggable divider between the sidebar and the thread? Wrap the panels in `<kc-resizable>`
with one `<kc-resizable-item>` each — the handles are inserted for you (up to 3 panels). Each item
takes a `size` (px or `%`) plus optional `min`/`max`; listen for `change` (`detail.sizes`) to
persist the layout.

```html
<style>
  html, body { margin: 0; height: 100%; }
  .app { display: flex; flex-direction: column; height: 100dvh; }
</style>

<div class="app">
  <kc-resizable orientation="horizontal" style="flex: 1; min-height: 0;">
    <kc-resizable-item size="25%" min="200px">
      <kc-conversations id="sidebar"></kc-conversations>
    </kc-resizable-item>
    <kc-resizable-item>
      <kc-chat id="chat"></kc-chat>
    </kc-resizable-item>
  </kc-resizable>
</div>

<script type="module">
  import '@kitn.ai/chat/elements';

  const resizable = document.querySelector('kc-resizable');
  resizable.addEventListener('kc-change', (e) => {
    console.log('panel sizes:', e.detail.sizes);
    // persist to localStorage, etc.
  });
</script>
```

You can also drop **standalone display elements** anywhere in your own page — `<kc-markdown>`,
`<kc-code-block>`, `<kc-artifact>` — to render rich AI content without adopting the whole chat.
Each element fills its container and is controlled via properties and events.

> **See it all assembled:** **[Examples → Full Chat App](?path=/story/examples-full-chat-app--default)**
> wires a sidebar, threaded markdown, a model switcher, a context meter, and a rich prompt input
> into one screen — a working reference to crib from.

> **Find every element:** browse the **Components** section in the sidebar. Each element's **API**
> tab lists its props, events, and copy-paste usage for HTML (and every other framework).

## Props & events

The rule for all elements: **rich data goes in as JS properties, interactions come out as events.**

```js
// ✅ Arrays and objects — always set as a JS property
el.messages = [{ id: '1', role: 'assistant', content: 'Hi' }];
el.conversations = myConversations;

// ✅ Events — addEventListener on the element (CustomEvents, they don't bubble)
el.addEventListener('kc-submit', (e) => console.log(e.detail.value));
el.addEventListener('kc-conversation-select', (e) => console.log(e.detail.id));
```

**Scalar attributes** (strings, booleans, numbers) can go directly in HTML markup:

```html
<!-- theme, placeholder, and loading are scalars → safe as attributes -->
<kc-chat
  theme="dark"
  placeholder="Ask anything…"
></kc-chat>
```

Key events by element:

| Element | Event | `detail` |
|---|---|---|
| `kc-chat` | `submit` | `{ value: string }` |
| `kc-conversations` | `conversationselect` | `{ id: string }` |
| `kc-conversations` | `newchat` | — |
| `kc-conversations` | `togglesidebar` | — |
| `kc-resizable` | `change` | `{ sizes: string[] }` |
