# Dropzone

## Description

A comprehensive file upload component with drag-and-drop functionality. The Dropzone component provides an intuitive interface for users to upload files either by dragging and dropping them onto the designated area or by clicking to open a file dialog. It supports file type restrictions, size limits, and multiple file uploads with customizable states for empty, loading, and uploaded scenarios.

## Aliases

- Dropzone
- File Upload
- File Drop
- Upload Area

## Props Breakdown

**Extends:** `ControlledFormComponentProps<File[]>`

| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| `empty` | `ReactNode` | - | No | Content to display when the dropzone is empty |
| `loading` | `ReactNode` | - | No | Content to display during file upload/processing |
| `uploaded` | `ReactNode` | - | No | Content to display when files are uploaded |
| `accept` | `{ [key: string]: readonly string[] }` | - | No | Accepted file types based on mime type |
| `maxSize` | `number` | - | No | Maximum file size in bytes |
| `maxFiles` | `number` | `1` | No | Maximum number of files to upload |
| `onFilesReset` | `() => void` | - | No | Callback when files are reset |
| `className` | `string` | - | No | Additional CSS class names |
| `initialValue` | `File[]` | - | No | Initial files value |
| `value` | `File[]` | - | No | Current files value |
| `onValueChange` | `(files: File[]) => void` | - | No | Callback when files change |
| `disabled` | `boolean` | `false` | No | Whether the dropzone is disabled |
| `required` | `boolean` | `false` | No | Whether file selection is required |
| `invalid` | `boolean` | `false` | No | Whether the current state is invalid |
| `id` | `string` | - | No | ID for the dropzone |

Plus all standard HTML div attributes (aria-*, data-*, etc.).

## Examples

### Basic Dropzone

```tsx
import { Dropzone } from '@delightui/components';

function BasicDropzoneExample() {
  const [files, setFiles] = useState<File[]>([]);

  return (
    <Dropzone
      value={files}
      onValueChange={setFiles}
      maxFiles={1}
      accept={{
        'image/*': ['.jpg', '.jpeg', '.png', '.gif']
      }}
    />
  );
}
```

### Custom States

```tsx
import { Dropzone, Text, Spinner, Button } from '@delightui/components';

function CustomStatesExample() {
  const [files, setFiles] = useState<File[]>([]);
  const [isUploading, setIsUploading] = useState(false);

  const handleUpload = async () => {
    setIsUploading(true);
    // Simulate upload
    await new Promise(resolve => setTimeout(resolve, 2000));
    setIsUploading(false);
  };

  return (
    <Dropzone
      value={files}
      onValueChange={setFiles}
      empty={
        <div style={{ textAlign: 'center', padding: '40px' }}>
          <Text size="large">Drop files here or click to upload</Text>
          <Text size="small" color="secondary">
            Supports JPG, PNG, GIF up to 10MB
          </Text>
        </div>
      }
      loading={
        <div style={{ textAlign: 'center', padding: '40px' }}>
          <Spinner />
          <Text>Uploading files...</Text>
        </div>
      }
      uploaded={
        <div style={{ textAlign: 'center', padding: '40px' }}>
          <Text color="success">✓ Files uploaded successfully</Text>
          <Button onClick={() => setFiles([])}>Upload More</Button>
        </div>
      }
      accept={{
        'image/*': ['.jpg', '.jpeg', '.png', '.gif']
      }}
      maxSize={10 * 1024 * 1024} // 10MB
      maxFiles={5}
    />
  );
}
```

### Multiple File Upload

```tsx
import { Dropzone, Text } from '@delightui/components';

function MultipleFileExample() {
  const [files, setFiles] = useState<File[]>([]);

  const handleFilesReset = () => {
    setFiles([]);
    console.log('Files reset');
  };

  return (
    <div>
      <Dropzone
        value={files}
        onValueChange={setFiles}
        onFilesReset={handleFilesReset}
        maxFiles={10}
        accept={{
          'image/*': ['.jpg', '.jpeg', '.png'],
          'application/pdf': ['.pdf'],
          'text/*': ['.txt', '.csv']
        }}
        maxSize={5 * 1024 * 1024} // 5MB per file
      />
      
      {files.length > 0 && (
        <div style={{ marginTop: '16px' }}>
          <Text>Selected files: {files.length}</Text>
          {files.map((file, index) => (
            <Text key={index} size="small">
              {file.name} ({(file.size / 1024).toFixed(1)} KB)
            </Text>
          ))}
        </div>
      )}
    </div>
  );
}
```

### Form Integration

```tsx
import { Form, FormField, Dropzone, Button } from '@delightui/components';

function FormDropzoneExample() {
  const handleSubmit = (data: any) => {
    console.log('Form submitted with files:', data.documents);
  };

  return (
    <Form onSubmit={handleSubmit}>
      <FormField
        name="documents"
        label="Upload Documents"
        required
        message="Please upload at least one document"
      >
        <Dropzone
          accept={{
            'application/pdf': ['.pdf'],
            'application/msword': ['.doc'],
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx']
          }}
          maxSize={20 * 1024 * 1024} // 20MB
          maxFiles={3}
        />
      </FormField>

      <Button actionType="submit">Submit Documents</Button>
    </Form>
  );
}
```

### Image Upload with Preview

```tsx
import { Dropzone, Text, Image } from '@delightui/components';

function ImageUploadExample() {
  const [files, setFiles] = useState<File[]>([]);
  const [previews, setPreviews] = useState<string[]>([]);

  useEffect(() => {
    // Create preview URLs for images
    const urls = files.map(file => {
      if (file.type.startsWith('image/')) {
        return URL.createObjectURL(file);
      }
      return null;
    }).filter(Boolean) as string[];

    setPreviews(urls);

    // Cleanup URLs on unmount
    return () => {
      urls.forEach(url => URL.revokeObjectURL(url));
    };
  }, [files]);

  return (
    <div>
      <Dropzone
        value={files}
        onValueChange={setFiles}
        accept={{
          'image/*': ['.jpg', '.jpeg', '.png', '.gif', '.webp']
        }}
        maxSize={5 * 1024 * 1024}
        maxFiles={1}
        uploaded={
          previews.length > 0 ? (
            <div style={{ textAlign: 'center', padding: '20px' }}>
              <Image
                src={previews[0]}
                alt="Preview"
                width={200}
                height={200}
                fit="Crop"
                style={{ borderRadius: '8px' }}
              />
              <Text>Image uploaded successfully</Text>
            </div>
          ) : undefined
        }
      />
    </div>
  );
}
```

### Disabled State

```tsx
import { Dropzone, Text } from '@delightui/components';

function DisabledDropzoneExample() {
  return (
    <Dropzone
      disabled
      empty={
        <div style={{ textAlign: 'center', padding: '40px' }}>
          <Text color="disabled">File upload is currently disabled</Text>
        </div>
      }
    />
  );
}
```

### Custom Styling

```tsx
import { Dropzone, Text } from '@delightui/components';

function CustomStyledDropzoneExample() {
  const [files, setFiles] = useState<File[]>([]);

  return (
    <Dropzone
      value={files}
      onValueChange={setFiles}
      className="custom-dropzone"
      style={{
        border: '2px dashed #007bff',
        borderRadius: '12px',
        backgroundColor: '#f8f9fa'
      }}
      empty={
        <div style={{ 
          textAlign: 'center', 
          padding: '60px 20px',
          color: '#007bff'
        }}>
          <Text size="large">📁 Drop your files here</Text>
          <Text size="small">or click to browse</Text>
        </div>
      }
    />
  );
}
```

### Error Handling

```tsx
import { Dropzone, Text } from '@delightui/components';

function ErrorHandlingExample() {
  const [files, setFiles] = useState<File[]>([]);
  const [error, setError] = useState<string>('');

  const handleFileChange = (newFiles: File[]) => {
    setError('');
    
    // Validate files
    const invalidFiles = newFiles.filter(file => {
      if (file.size > 10 * 1024 * 1024) {
        setError(`File "${file.name}" is too large. Maximum size is 10MB.`);
        return true;
      }
      return false;
    });

    if (invalidFiles.length === 0) {
      setFiles(newFiles);
    }
  };

  return (
    <div>
      <Dropzone
        value={files}
        onValueChange={handleFileChange}
        invalid={!!error}
        accept={{
          'image/*': ['.jpg', '.jpeg', '.png'],
          'application/pdf': ['.pdf']
        }}
        maxSize={10 * 1024 * 1024}
        maxFiles={3}
      />
      
      {error && (
        <Text color="error" size="small" style={{ marginTop: '8px' }}>
          {error}
        </Text>
      )}
    </div>
  );
}
```