# lexical-ai-tools

[![npm](https://img.shields.io/npm/v/lexical-ai-tools)](https://www.npmjs.com/package/lexical-ai-tools)
[![npm bundle size](https://img.shields.io/bundlephobia/minzip/lexical-ai-tools)](https://bundlephobia.com/package/lexical-ai-tools)
[![license](https://img.shields.io/npm/l/lexical-ai-tools)](./LICENSE)

AI editing primitives for [Lexical](https://lexical.dev) — selection rewrite, inline diff preview, and low-level tree ops.

- **Provider-agnostic** — bring your own AI (OpenAI, Anthropic, local, etc.)
- **Headless** — no UI, you build the toolbar
- **Small** — ~10 KB, zero runtime deps beyond Lexical
- **TypeScript-first** — full types + JSDoc

## Install

```bash
pnpm add lexical-ai-tools
```

Peers: `lexical`, `@lexical/react`, `@lexical/markdown`, `react`

## Usage

### 1. Register the node

```tsx
import { DiffHighlightNode } from 'lexical-ai-tools';

const config = {
  nodes: [DiffHighlightNode],
  theme: {
    diffHighlight: {
      inserted: 'bg-green-100 text-green-900',
      deleted: 'bg-red-100 text-red-900 line-through',
    },
  },
};
```

### 2. AI Rewrite — `useAIEdit`

```tsx
import { useAIEdit } from 'lexical-ai-tools';

const { isProcessing, selectedText, rewrite } = useAIEdit({
  editor,
  onRewrite: async (text, instruction) => {
    const res = await fetch('/api/rewrite', {
      method: 'POST',
      body: JSON.stringify({ text, instruction }),
    });
    return (await res.json()).result;
  },
});

// rewrite('Make it shorter')
// rewriteWithPreset('formal')
```

### 3. Diff Preview — `AIDiffPlugin`

```tsx
import { AIDiffPlugin } from 'lexical-ai-tools';
import { TRANSFORMERS } from '@lexical/markdown';

<AIDiffPlugin
  diff={{ newMarkdown: '# Updated\n\nNew content.' }}
  transformers={TRANSFORMERS}
  onCleared={() => setDiff(null)}
/>
```

### 4. Low-level ops

```tsx
import { $captureSelection, $replaceSelection } from 'lexical-ai-tools';

// Before async AI call
let saved;
editor.getEditorState().read(() => { saved = $captureSelection(); });

// After AI responds
editor.update(() => { $replaceSelection(saved, result); });
```

## API

| Export | Type | Description |
|---|---|---|
| `useAIEdit` | Hook | Selection rewrite lifecycle |
| `AIDiffPlugin` | Component | Diff preview with highlight + fade |
| `DiffHighlightNode` | Node | Inline diff marks |
| `$captureSelection` | `$` fn | Snapshot range selection |
| `$replaceSelection` | `$` fn | Replace saved selection |
| `$collectBlockTexts` | `$` fn | Block text array |
| `$highlightChangedBlocks` | `$` fn | Mark changed blocks |
| `$clearDiffHighlights` | `$` fn | Remove all diff marks |

## License

MIT
