# react-markdown-messages

A lightweight, streaming-first React component library for rendering markdown messages with syntax highlighting, math support, task lists, and more. Built for AI chat interfaces.

## Features

- **Streaming Support** — Render markdown in real-time as text streams in, no waiting for completion
- **Syntax Highlighting** — 190+ languages supported via highlight.js
- **KaTeX Math** — Beautiful LaTeX math rendering with inline and block equations
- **Interactive Task Lists** — Clickable checkboxes with change callbacks
- **Code Editing** — Edit code blocks inline with copy and collapse
- **RTL Support** — Full right-to-left language support for Arabic, Hebrew, and more
- **TypeScript** — Written in TypeScript with full type definitions
- **Zero External UI Dependencies** — No heavy UI framework required

## Installation

```bash
npm install react-markdown-messages
```

Or with your favorite package manager:

```bash
pnpm add react-markdown-messages
yarn add react-markdown-messages
bun add react-markdown-messages
```

## Quick Start

### Basic Usage

```tsx
import { Markdown } from 'react-markdown-messages';

function App() {
  return (
    <Markdown
      content="# Hello World\n\nThis is **streaming** markdown!"
      done={true}
    />
  );
}
```

### Streaming Example

```tsx
import { useState, useEffect } from 'react';
import { Markdown } from 'react-markdown-messages';

function StreamingChat() {
  const [content, setContent] = useState('');
  const [done, setDone] = useState(false);

  useEffect(() => {
    const text = 'Your streaming content here...';
    let i = 0;

    const interval = setInterval(() => {
      if (i < text.length) {
        setContent(text.slice(0, ++i));
      } else {
        setDone(true);
        clearInterval(interval);
      }
    }, 50);

    return () => clearInterval(interval);
  }, []);

  return <Markdown content={content} done={done} />;
}
```

### With Chat Messages

```tsx
import { Messages } from 'react-markdown-messages';

function Chat() {
  const messages = [
    { id: '1', role: 'user', content: 'Hello!' },
    { id: '2', role: 'assistant', content: 'Hi there!' },
  ];

  return (
    <Messages
      messages={messages}
      onEdit={(id, content) => console.log(id, content)}
      onDelete={(id) => console.log('delete', id)}
      onRate={(id, rating) => console.log(id, rating)}
    />
  );
}
```

## Components

### `<Markdown />`

Core markdown rendering component.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `id` | `string` | `''` | Unique identifier |
| `content` | `string` | — | Markdown content |
| `done` | `boolean` | `true` | Streaming complete flag |
| `model` | `string` | `null` | Model name to display |
| `editCodeBlock` | `boolean` | `true` | Allow code editing |
| `paragraphTag` | `'p' \| 'span'` | `'p'` | Paragraph element type |
| `onTaskClick` | `function` | — | Task list checkbox callback |
| `onSourceClick` | `function` | — | Citation click callback |
| `onSave` | `function` | — | Code save callback |

### `<Messages />`

Complete chat message list component with auto-scroll.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `messages` | `MessageType[]` | — | Array of messages |
| `autoScroll` | `boolean` | `true` | Auto-scroll to bottom |
| `onEdit` | `function` | — | Message edit callback |
| `onDelete` | `function` | — | Message delete callback |
| `onRate` | `function` | — | Message rating callback |
| `onRegenerate` | `function` | — | Regenerate response callback |
| `onContinue` | `function` | — | Continue generating callback |
| `editCodeBlock` | `boolean` | `true` | Allow code editing |
| `readOnly` | `boolean` | `false` | Disable all interactions |

### `<CodeBlock />`

Standalone code block component with syntax highlighting, editing, and collapse.

### `<useStreaming />` Hook

Simulate streaming text output for demos.

```tsx
const { content, isStreaming, progress, start, stop, reset } = useStreaming(initialContent, {
  speed: 100,     // characters per second
  chunkSize: 5,   // characters per chunk
  onComplete: () => console.log('Done!'),
});
```

## API Reference

### Types

```tsx
interface Message {
  id: string;
  role: 'user' | 'assistant';
  content: string;
  model?: string;
  timestamp?: number;
  files?: { type: string; url: string }[];
  annotation?: {
    rating?: number;
  };
}

interface MarkdownProps {
  id?: string;
  content: string;
  done?: boolean;
  model?: string | null;
  editCodeBlock?: boolean;
  paragraphTag?: 'p' | 'span';
  sourceIds?: string[];
  onSave?: (data: { raw: string; oldContent: string; newContent: string }) => void;
  onUpdate?: () => void;
  onPreview?: () => void;
  onSourceClick?: (sourceId: string) => void;
  onTaskClick?: (data: TaskClickData) => void;
}
```

## Peer Dependencies

```json
{
  "peerDependencies": {
    "react": ">=18.0.0",
    "react-dom": ">=18.0.0"
  }
}
```

## License

MIT
