npm package: @miaopazzz/react-upload
Description: 基于 React、Tailwind CSS 4、shadcn 风格的上传组件（裁剪/多文件/粘贴导入），提取自项目内可复用组件
Author: miaopazzz
Latest version: 0.1.4

# @miaopazzz/react-upload

基于 React + Tailwind CSS 4 + Radix(shadcn 风格) 的上传组件集合，支持：
- 拖拽/点击选择文件
- 单文件与多文件模式
- 图片裁剪（基于 Cropper.js）
- 剪贴板导入图片（右键菜单或快捷键粘贴）
- 文件类型与提示信息展示

## 安装与依赖

安装（稳定版）：

```bash
# npm
npm i @miaopazzz/react-upload@latest
# 或 pnpm / yarn
pnpm add @miaopazzz/react-upload@latest
yarn add @miaopazzz/react-upload@latest
```

本包为自用组件，要求宿主项目已安装并配置以下依赖（peerDependencies）：
- react、react-dom（>=18）
- react-dropzone
- react-cropper、cropperjs（裁剪功能）
- lucide-react（图标，仅少量使用）
- sonner（消息提示）
- tailwind-merge、clsx、class-variance-authority、@radix-ui/react-*（UI 基座）

样式：请在应用入口引入 Cropper 的样式
```ts
import 'cropperjs/dist/cropper.css';
// （推荐）引入本包独立样式，保障未扫描包源码时的 UI 一致性
import '@miaopazzz/react-upload/styles.css';
```

## 快速使用
```tsx
import { ImageCropUploader } from '@miaopazzz/react-upload';

// 单文件（默认启用裁剪）
<ImageCropUploader
  value={fileList}
  onChange={setFileList}
  inputName="avatar"
  accept={{ 'image/*': [] }}
  cropSize={{ width: 800, height: 800 }}
  maxSize={2 * 1024 * 1024}
/>

// 多文件（不裁剪）
<ImageCropUploader
  value={files}
  onChange={setFiles}
  multiple
  // 不限制类型：去掉 accept 或传 undefined
  accept={undefined}
  // 不限制大小（按需）：
  maxSize={Number.POSITIVE_INFINITY}
/>
```

### 多文件“异步队列上传”（推荐）
```tsx
import { QueueImageUploader } from '@miaopazzz/react-upload';

// 选择即入队，组件内部并发上传（XHR），带进度/状态
<QueueImageUploader
  inputName="images"
  endpoint={'/upload'}
  // 每个文件的额外字段（FormData）：
  extraFields={() => ({ key: 'value' })}
  concurrency={3}
  // 进度样式（可选）：使用宿主 Tailwind 类（若确保被扫描生成）
  progressClasses={{ container: 'h-1 bg-muted rounded-full', bar: 'bg-primary' }}
  onAllDone={() => console.log('all done')}
/> 
```
说明：
- `QueueImageUploader` 负责并发队列、XHR 上传、CSRF 头注入、进度/状态渲染；页面仅传 `endpoint/extraFields/concurrency` 等配置。
- 进度条默认采用 CSS 变量颜色（无需 Tailwind 支持），若希望使用 Tailwind 类可通过 `progressClasses` 传入。

## 行为说明（重要）
- 裁剪模式跳过大小限制（单文件模式）：
  - 当 `enableCrop=true` 且传入的是可裁剪图片时，组件会直接进入裁剪流程，并“忽略 `maxSize` 限制”。
  - 原因：裁剪会在前端重新导出较低质量/尺寸的图片，最终提交的文件体积通常远小于原图，因此无需在选择阶段拦截。
  - 若未启用裁剪或文件并非可裁剪图片，则按 `maxSize` 常规校验。
- 多文件模式不支持裁剪：
  - 保持简单直观，支持文件列表展示与移除；如需限制类型或大小，可通过 `accept / maxSize` 控制。

### 队列上传 vs 表单同步提交
- `ImageCropUploader`：只负责“选择/预览/裁剪”，不发网络请求。常用于“表单同步提交”场景。
- `QueueImageUploader`：组件内“选择即入队并上传”，一次多个文件，失败不影响其他文件，带进度/完成回调。

## 主要 Props
- `value: FileList | null`、`onChange(next: FileList | null)`：受控文件状态
- `multiple?: boolean`：是否启用多文件模式（默认 false）
- `enableCrop?: boolean`：单文件模式下是否启用裁剪（默认 true）
- `accept?: Accept`：同 react-dropzone 的 `accept`
- `maxSize?: number`：单文件/多文件的大小限制（字节）。单文件+裁剪时会被跳过。
- `cropSize?: { width: number; height: number }`：裁剪目标参考尺寸（影响提示与裁剪比例）
- `initialUrl?: string`：编辑场景下的已有图片地址
- `inputName?: string`：用于表单提交的隐藏 `input[type=file]` 名称

### QueueImageUploader Props（多文件异步队列）
- `endpoint: string | (file) => string`：单文件上传 JSON 接口地址（或按文件决定端点）。
- `method?: 'POST'|'PUT'|'PATCH'`：HTTP 方法（默认 `POST`）。
- `headers?: Record<string,string>`：额外请求头；组件会自动注入 `X-CSRF-TOKEN`（从 Cookie 读取）与 `X-Requested-With`。
- `extraFields?: (file) => Record<string,string|Blob>`：每个文件的额外 FormData 字段（如 `is_homepage`）。
- `concurrency?: number`：并发数（默认 3）。
- `accept?: Accept`、`maxSize?: number`、`hints?`：与 `ImageCropUploader` 类似。
- `onAllDone?: () => void`：全部文件状态为 `success` 时触发。
- `progressClasses?: { container?: string; bar?: string }`：进度条容器/条自定义类名（可使用宿主 Tailwind 类）。

进度条主题（CSS 变量）
- 默认使用以下 CSS 变量（无需 Tailwind 也能显示）：
  - `--ru-progress-bg`（容器背景，默认回退到 `--muted`）
  - `--ru-progress-fg`（进度颜色，默认回退到 `--primary`）
- 可在宿主项目主题中覆盖：
```css
:root {
  --ru-progress-bg: oklch(0.92 0 0);
  --ru-progress-fg: oklch(0.65 0.12 240);
}
```

## 许可证
MIT