# md-editor

基于 React、Milkdown、Monaco Editor 和 Tailwind CSS 的 Markdown 编辑器组件。项目同时包含组件库源码和 Vite 演示应用，支持所见即所得编辑、Markdown 源码编辑、自动保存状态展示，以及常用 Markdown 扩展能力。

## 功能特性

- 所见即所得 Markdown 编辑，基于 Milkdown。
- Markdown 源码面板，基于 Monaco Editor，支持与预览区域滚动同步。
- 常用工具栏：标题、粗体、斜体、删除线、下划线、行内代码、链接、列表。
- 内容插入：图片、表格、表情、GitHub Alert、数学公式、Mermaid 图表。
- 扩展渲染：GFM、代码块、表格、KaTeX 数学公式、Mermaid、容器块。
- 只读模式下隐藏工具栏，适合做 Markdown 内容预览。
- 受控和非受控两种使用方式。

## 技术栈

- React 19
- TypeScript
- Vite
- Milkdown
- Monaco Editor
- Tailwind CSS 4
- Biome

## 安装

在外部项目中安装：

```bash
npm install @dingshaohua.com/md-editor
```

也可以使用 pnpm 或 yarn：

```bash
pnpm add @dingshaohua.com/md-editor
yarn add @dingshaohua.com/md-editor
```

## 作为组件使用

```tsx
import MdEditor, { type MilkdownEditorProps } from '@dingshaohua.com/md-editor';
import { useState } from 'react';

type SaveStatus = NonNullable<MilkdownEditorProps['saveStatus']>;

export default function App() {
  const [value, setValue] = useState('# Hello md-editor');
  const [saveStatus, setSaveStatus] = useState<SaveStatus>('saved');

  const handleSave = async (nextValue: string) => {
    setSaveStatus('saving');

    try {
      await saveMarkdown(nextValue);
      setSaveStatus('saved');
    } catch {
      setSaveStatus('error');
    }
  };

  return (
    <div style={{ height: 600 }}>
      <MdEditor
        value={value}
        saveStatus={saveStatus}
        onChange={(nextValue) => {
          setValue(nextValue);
          setSaveStatus('unsaved');
        }}
        onSave={handleSave}
      />
    </div>
  );
}
```

编辑器会撑满父容器，使用时需要给外层容器提供明确高度。

## Props

| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `value` | `string` | - | 受控模式下的 Markdown 内容 |
| `defaultValue` | `string` | `''` | 非受控模式下的初始 Markdown 内容 |
| `onChange` | `(value: string) => void` | - | 内容变化回调 |
| `saveStatus` | `'unsaved' \| 'saving' \| 'saved' \| 'error'` | `'unsaved'` | 工具栏保存按钮状态 |
| `onSave` | `(value: string) => void \| Promise<void>` | - | 点击保存按钮时触发 |
| `readOnly` | `boolean` | `false` | 是否只读；只读时隐藏工具栏和源码编辑面板 |
| `imgUploadHandler` | `(file: File) => Promise<string>` | - | 本地图片上传回调；返回图片 URL，不传时使用 base64 data URL |

## 本地开发

本项目使用 pnpm 管理依赖。

```bash
# 安装依赖
pnpm install

# 启动演示应用
pnpm dev

# 构建演示应用
pnpm build

# 构建组件库
pnpm build:lib

# 预览演示应用构建结果
pnpm preview

# 格式化、Lint 和导入排序
pnpm biome
```

## 目录结构

```text
.
├── lib/                  # 编辑器组件库源码
│   ├── components/       # 编辑器、工具栏、UI 组件
│   ├── hooks/            # 编辑器同步和受控状态 Hooks
│   ├── plugins/          # Milkdown 扩展插件
│   ├── store/            # 编辑器状态
│   └── main.ts           # 组件库入口
├── src/                  # Vite 演示应用
├── public/               # 静态资源
├── vite.config.ts        # 演示应用构建配置
└── vite.lib.config.ts    # 组件库构建配置
```

## 构建产物

组件库构建命令：

```bash
pnpm build:lib
```

构建结果输出到 `dist/`，入口为：

- `dist/main.js`
- `dist/main.d.ts`

演示应用构建命令：

```bash
pnpm build
```

构建结果输出到 `dist-demo/`。

## 代码规范

项目使用 Biome 管理格式化、Lint 和导入排序：

```bash
pnpm biome
```
