npm package: @rizal_ncc/chatbot-component
Description: Reusable chatbot UI component with framework-agnostic and Web Component exports.
Latest version: 1.0.3

# @rizalncc/chatbot-component

Reusable, framework-agnostic chatbot UI built with vanilla JavaScript, Tailwind CSS, and shadcn-inspired styling. The package exposes both a programmatic API (`Chatbot`/`createChat`) and a Web Component (`<chatbot-widget>`) so it can drop into React, Next.js, Vue, or plain HTML.

## Installation

```bash
npm install @rizalncc/chatbot-component
# or
pnpm add @rizalncc/chatbot-component
# or
yarn add @rizalncc/chatbot-component
```

The package ships prebuilt CSS. Import it once in your app for the class-based styles:

```js
import "@rizalncc/chatbot-component/styles.css";
```

## Usage Examples

### React (with `useEffect`)

```jsx
import { useEffect, useRef } from "react";
import { Chatbot } from "@rizalncc/chatbot-component";
import "@rizalncc/chatbot-component/styles.css";

export default function SupportChat() {
  const containerRef = useRef(null);

  useEffect(() => {
    if (!containerRef.current) return;

    const chat = new Chatbot({
      target: containerRef.current,
      layout: "widget",
      headerTitle: "Bawana Assistant",
      async onSubmit({ input, appendAssistantMessage }) {
        appendAssistantMessage({ content: `You said: ${input}` });
      },
    });

    return () => chat.stop("disconnect");
  }, []);

  return <div ref={containerRef} style={{ width: 360, height: 520 }} />;
}
```

### Vue 3 (Composition API)

```vue
<script setup>
import { onMounted, onBeforeUnmount, ref } from "vue";
import { createChat } from "@rizalncc/chatbot-component";
import "@rizalncc/chatbot-component/styles.css";

const host = ref(null);
let chatInstance;

onMounted(() => {
  chatInstance = createChat({
    target: host.value,
    headerTitle: "Bawana Assistant",
    onSubmit({ appendAssistantMessage }) {
      appendAssistantMessage({ content: "Halo dari Vue!" });
    },
  });
});

onBeforeUnmount(() => {
  chatInstance?.stop("disconnect");
});
</script>

<template>
  <div ref="host" style="width: 100%; max-width: 420px; height: 540px" />
</template>
```

### Vanilla HTML (Web Component)

```html
<link rel="stylesheet" href="/node_modules/@rizalncc/chatbot-component/dist/style.css">
<script type="module" src="/node_modules/@rizalncc/chatbot-component/dist/chatbot-element.js"></script>

<chatbot-widget
  layout="widget"
  header-title="Bawana Assistant"
  suggestions="Apa saja layanan Bawana?|Bagaimana cara memulai?"
></chatbot-widget>

<script type="module">
  const widget = document.querySelector("chatbot-widget");

  widget.addEventListener("chatbot-submit", async (event) => {
    const { input, appendAssistantMessage, resolve } = event.detail;

    // Replace with real API call
    appendAssistantMessage({ content: `Pencarian: ${input}` });
    resolve();
  });
</script>
```

## Runtime API

### `new Chatbot(options)` / `createChat(options)`

| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `target` | `Element | string` | required | Host element or selector where the chat UI mounts. |
| `initialMessages` | `ChatMessage[]` | `[]` | Preload conversation history. |
| `suggestions` | `string[]` | preset prompts | Optional quick-start prompts shown when empty. |
| `placeholder` | `string` | `"Ketik pesanmu di sini..."` | Input placeholder text. |
| `onSubmit` | `ChatSubmitHandler` | echo simulation | Async handler invoked when the user sends a message. Use helpers on the payload to append responses. |
| `onStop` | `ChatStopHandler` | no-op | Runs when the stop button or `stop()` is invoked. |
| `allowAttachments` | `boolean` | `true` | Toggle file upload chip behaviour. |
| `userInitials` / `assistantInitials` | `string` | `"YOU"` / `"AI"` | Avatar initials. |
| `showHeader` | `boolean` | `true` | Toggle header block. |
| `headerTitle` / `headerDescription` | `string` | sample copy | Header content. |
| `layout` | `"page" | "widget"` | `"page"` | Controls padding + surface style. |

Useful instance methods:

- `chat.appendMessage(message)` – push a new message.
- `chat.setMessages(messages)` – replace the conversation.
- `chat.updateMessage(id, updater)` – merge/replace a message.
- `chat.stop(origin)` – cancel an in-flight response and trigger `onStop`.
- `chat.focusInput()` – focus the textarea programmatically.

### Web Component Attributes

| Attribute | Type | Default |
| --- | --- | --- |
| `layout` | `widget` \| `page` | `widget` |
| `header-title` / `header-description` | `string` | — |
| `placeholder` | `string` | inherited |
| `suggestions` | string list separated by `|` or newline | presets |
| `allow-attachments` | `"true" | "false"` | `true` |
| `show-header` | `"true" | "false"` | `true` |
| `user-initials` / `assistant-initials` | `string` | `YOU` / `AI` |

### Web Component Events & Methods

- `chatbot-submit` – fired when the user sends a message. `event.detail` matches `ChatSubmitPayload` plus:
  - `response`: set to string/object/Promise to resolve the submission.
  - `resolve(value)` helper to set `response` imperatively.
- `chatbot-stop` – emitted when generation stops (`origin` in detail).

Methods:

```js
const widget = document.querySelector("chatbot-widget");
widget.configure({ headerTitle: "Live Support" });
widget.onSubmit = async ({ input, appendAssistantMessage }) => {
  appendAssistantMessage({ content: `Handled: ${input}` });
};
```

### Registering the element manually

If you prefer a custom tag name:

```js
import { registerChatbotElement } from "@rizalncc/chatbot-component";

registerChatbotElement("support-chat");
```

## Project Structure

```
chatbot-components/
├─ src/
│  ├─ core/           # Chat implementation
│  ├─ elements/       # Web Component wrapper + entry
│  ├─ styles/         # Tailwind-powered styling
│  ├─ element.js      # Web Component build entry (for <script type="module">)
│  └─ index.js        # Library entry (ESM/CJS)
├─ dist/              # Build output (generated)
├─ types/             # TypeScript definitions
├─ instruction/       # Project guidance notes
└─ README.md
```

## Building & Publishing

```bash
npm run build
```

Outputs:

- `dist/chatbot-component.js` – ESM bundle.
- `dist/chatbot-component.cjs` – CommonJS bundle.
- `dist/chatbot-element.js` – module script that auto-registers `<chatbot-widget>`.
- `dist/style.css` – compiled Tailwind + component styles.

Before publishing to npm:

1. Update version in `package.json`.
2. Run `npm run build` to refresh `dist/` and `types/`.
3. Execute `npm publish --access public`.

## Local Playground

For local exploration, the Vite dev server still mounts `src/main.js`:

```bash
npm install
npm run dev
```

Configure OpenRouter keys in `.env.local` if you want to test the example integration (`VITE_OPENROUTER_API_KEY`, `VITE_OPENROUTER_MODEL`).

## License

MIT © Rizal NCC