npm package: @howells/stow-react
Description: React components for Stow file storage
Latest version: 2.4.0

# @howells/stow-react

React components for [Stow](https://stow.sh) file storage.

## Installation

```bash
npm install @howells/stow-react
# or
pnpm add @howells/stow-react
# or
yarn add @howells/stow-react
```

## Quick Start

```tsx
import { UploadDropzone } from "@howells/stow-react";

function MyComponent() {
  return (
    <UploadDropzone
      endpoint="/api/upload"
      onUploadComplete={(files) => {
        console.log("Uploaded:", files);
      }}
      onUploadError={(error) => {
        console.error("Error:", error.message);
      }}
    />
  );
}
```

## Components

### `<UploadDropzone>`

A drag-and-drop file upload zone with built-in progress tracking.

```tsx
<UploadDropzone
  // Required
  endpoint="/api/upload"
  // Callbacks
  onUploadComplete={(files) => console.log(files)}
  onUploadError={(error) => console.error(error)}
  onUploadProgress={(progress) => console.log(progress.percent)}
  onUploadBegin={(files) => console.log("Starting upload...")}
  // File restrictions
  accept="image/*" // Accepted file types
  maxSize={10 * 1024 * 1024} // Max 10MB
  maxFiles={5} // Max 5 files
  multiple={true} // Allow multiple files
  // Appearance
  className="my-dropzone"
  disabled={false}
  // Optional route for organizing files
  route="avatars"
/>
```

## Props

| Prop               | Type                                 | Default  | Description                            |
| ------------------ | ------------------------------------ | -------- | -------------------------------------- |
| `endpoint`         | `string`                             | required | Your server upload endpoint            |
| `route`            | `string`                             | -        | Optional route for organizing files    |
| `onUploadComplete` | `(files: UploadedFile[]) => void`    | -        | Called when all files uploaded         |
| `onUploadError`    | `(error: Error) => void`             | -        | Called on upload error                 |
| `onUploadProgress` | `(progress: UploadProgress) => void` | -        | Called with progress updates           |
| `onUploadBegin`    | `(files: File[]) => void`            | -        | Called when upload starts              |
| `accept`           | `string`                             | -        | Accepted file types (e.g., "image/\*") |
| `maxSize`          | `number`                             | -        | Maximum file size in bytes             |
| `maxFiles`         | `number`                             | `10`     | Maximum number of files                |
| `multiple`         | `boolean`                            | `true`   | Allow multiple file selection          |
| `className`        | `string`                             | -        | Custom CSS class                       |
| `disabled`         | `boolean`                            | `false`  | Disable the dropzone                   |

## Types

```typescript
type UploadedFile = {
  key: string;
  url: string | null;
  name: string;
  size: number;
  type: string;
};

type UploadProgress = {
  file: File;
  loaded: number;
  total: number;
  percent: number;
};
```

## Styling

The component uses inline styles by default. Override with your own CSS:

```tsx
<UploadDropzone endpoint="/api/upload" className="custom-dropzone" />
```

```css
.custom-dropzone {
  border: 2px dashed #3b82f6;
  border-radius: 12px;
  padding: 3rem;
  background: #f8fafc;
}
```

## Server Setup

This component requires a server endpoint. Use `@howells/stow-next` for easy setup:

```typescript
// app/api/upload/route.ts
import { createUploadHandler } from "@howells/stow-next";
import { StowServer } from "@howells/stow-server";

const stow = new StowServer(process.env.STOW_API_KEY!);

export const POST = createUploadHandler({
  stow,
  maxSize: 10 * 1024 * 1024,
  allowedTypes: ["image/*"],
});
```

## License

MIT