# file-dropzone

File upload with drag & drop, type/size validation, image previews, and multi-file support.

## Markup

```html
<div data-c42-dropzone>
  <input data-c42-dropzone-input type="file" />
  <div data-c42-dropzone-zone>
    <strong>Drop files here</strong>
    <span>or click to browse</span>
  </div>
  <p data-c42-dropzone-error hidden></p>
  <ul data-c42-dropzone-list></ul>
</div>
```

### Optional preview container

Add `data-c42-dropzone-preview` for image thumbnail rendering when `previews: true`:

```html
<div data-c42-dropzone-preview></div>
```

## Options

```ts
import { FileDropzone } from '@42/core/file-dropzone';

new FileDropzone(root, {
  accept: 'image/*',          // comma-separated: '.pdf,.csv', 'image/png', 'image/*'
  maxSize: 2 * 1024 * 1024,   // max bytes per file
  multiple: true,
  maxFiles: 5,                // max files retained (default: 1 if !multiple)
  disabled: false,
  validate: undefined,        // (file: File) => true | 'error message'
  previews: true,             // render data-URL previews for images
});
```

## Events

| Event | Detail |
|-------|--------|
| `dropzone:change` | `{ files: File[] }` |
| `dropzone:reject` | `{ file: File, reason: DropzoneRejectReason, message?: string }` |

### Reject reasons

| Reason | When |
|--------|------|
| `too-large` | File exceeds `maxSize` |
| `unaccepted-type` | File doesn't match `accept` |
| `max-files` | Adding would exceed `maxFiles` |
| `invalid` | Custom `validate` returned a string |

## Behaviour

- Clicking `[data-c42-dropzone-zone]` opens the native file picker.
- Dragging files over the zone adds `data-state="active"` (use for styling).
- Accepted files are rendered as `<li>` in `[data-c42-dropzone-list]` with a remove button.
- Rejected files trigger `dropzone:reject` and show the error in `[data-c42-dropzone-error]`.
- `data-state="disabled"` is set when `disabled: true`.

## Methods

| Method | Description |
|--------|-------------|
| `getFiles()` | Returns current `File[]` |
| `clear()` | Remove all files |
| `destroy()` | Cleanup |
