@atom_design/upload
v1.0.0
Published
A React Native file upload component with progress indicator, image picker, and camera fallback. Part of the Atom Design System.
Readme
@atom_design/upload
A React Native file upload component with progress indicator, image picker, and camera fallback. Part of the Atom Design System.
Features
- 📁 File Picker - Select images/videos from library
- 📷 Camera Fallback - Automatic camera fallback if library fails
- 📊 Progress Indicator - Visual upload progress bar
- 📏 Size Validation - Configurable max file size
- 🎨 Customizable - Style all elements with custom props
- ♿ Accessible - Full screen reader support
- 💪 TypeScript - Full type definitions included
📦 Installation
npm install @atom_design/upload
# or
yarn add @atom_design/uploadPeer Dependencies
npm install react-native-image-picker react-native-progress react-native-vector-icons prop-typesPlatform Setup
iOS:
cd ios && pod installAdd to Info.plist:
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photo library to upload files</string>
<key>NSCameraUsageDescription</key>
<string>We need access to your camera to take photos</string>Android:
Add to AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />🚀 Basic Usage
import React from 'react';
import { View } from 'react-native';
import UploadField from '@atom_design/upload';
const App = () => {
const handleFileSelected = (file) => {
console.log('Selected:', file);
};
const handleUploadComplete = (file) => {
console.log('Uploaded:', file);
// Call your upload API here
};
return (
<View style={{ flex: 1, padding: 20 }}>
<UploadField
title="Upload Document"
maxSizeMB={10}
onFileSelected={handleFileSelected}
onUploadComplete={handleUploadComplete}
/>
</View>
);
};
export default App;🧩 Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| onFileSelected | (file) => void | - | Callback when file is selected |
| onUploadComplete | (file) => void | - | Callback when upload completes |
| onFileRemoved | (file) => void | - | Callback when file is removed |
| maxSizeMB | number | 50 | Maximum file size in MB |
| mediaType | 'photo' \| 'video' \| 'mixed' | 'mixed' | Allowed media type |
| title | string | 'Upload File' | Title above upload field |
| placeholder | string | 'Select a file' | Placeholder text |
| uploadButtonText | string | 'Upload' | Button text |
| disabled | boolean | false | Disable upload |
| showCamera | boolean | true | Show camera fallback |
| containerStyle | ViewStyle | - | Container style |
| uploadBoxStyle | ViewStyle | - | Upload box style |
| progressColor | string | '#52B898' | Progress bar color |
| testID | string | - | Test ID |
📁 File Object
When a file is selected, the component returns:
interface UploadedFile {
uri: string; // File URI
name: string; // File name
size: number; // Size in bytes
type: string; // MIME type
width?: number; // Image/video width
height?: number; // Image/video height
duration?: number; // Video duration
}🧪 Test Screen Example
import React, { useState } from 'react';
import { SafeAreaView, ScrollView, Text, StyleSheet, View } from 'react-native';
import UploadField from '@atom_design/upload';
const UploadTestScreen = () => {
const [uploadedFile, setUploadedFile] = useState(null);
return (
<SafeAreaView style={styles.container}>
<ScrollView contentContainerStyle={styles.content}>
<Text style={styles.header}>@atom_design/upload</Text>
{/* Basic Upload */}
<UploadField
title="Profile Picture"
placeholder="Select an image"
mediaType="photo"
maxSizeMB={5}
onFileSelected={(file) => console.log('Selected:', file.name)}
onUploadComplete={(file) => setUploadedFile(file)}
/>
{/* Video Upload */}
<View style={styles.spacing} />
<UploadField
title="Upload Video"
placeholder="Select a video"
mediaType="video"
maxSizeMB={100}
progressColor="#3498db"
onFileSelected={(file) => console.log('Video:', file.name)}
/>
{/* Custom Styled */}
<View style={styles.spacing} />
<UploadField
title="Upload Document"
placeholder="Choose file"
uploadButtonText="Browse"
maxSizeMB={25}
progressColor="#d9232d"
uploadBoxStyle={styles.customUpload}
onFileSelected={(file) => console.log('Doc:', file.name)}
/>
{/* Disabled */}
<View style={styles.spacing} />
<UploadField
title="Disabled Upload"
disabled
/>
{/* Upload Status */}
{uploadedFile && (
<View style={styles.status}>
<Text style={styles.statusText}>
Last uploaded: {uploadedFile.name}
</Text>
</View>
)}
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
content: {
padding: 20,
},
header: {
fontSize: 24,
fontWeight: 'bold',
textAlign: 'center',
marginBottom: 24,
color: '#333',
},
spacing: {
height: 24,
},
customUpload: {
borderStyle: 'dashed',
borderColor: '#d9232d',
},
status: {
marginTop: 24,
padding: 12,
backgroundColor: '#e8f5e9',
borderRadius: 8,
},
statusText: {
color: '#2e7d32',
fontSize: 14,
},
});
export default UploadTestScreen;🔧 Real Upload Integration
Replace the simulated upload with your API:
import UploadField from '@atom_design/upload';
const MyComponent = () => {
const uploadToServer = async (file) => {
const formData = new FormData();
formData.append('file', {
uri: file.uri,
type: file.type,
name: file.name,
});
const response = await fetch('https://api.example.com/upload', {
method: 'POST',
body: formData,
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.json();
};
return (
<UploadField
onFileSelected={async (file) => {
try {
const result = await uploadToServer(file);
console.log('Upload success:', result);
} catch (error) {
console.error('Upload failed:', error);
}
}}
/>
);
};📝 TypeScript
Full TypeScript support included:
import UploadField, { UploadedFile, UploadFieldProps } from '@atom_design/upload';
const handleFile = (file: UploadedFile) => {
console.log(file.name, file.size);
};
<UploadField
title="Upload"
onFileSelected={handleFile}
/>♿ Accessibility
The component includes full accessibility support:
- Proper
accessibilityRoleon all interactive elements - Descriptive labels for screen readers
- Touch target sizes meet accessibility guidelines
- Status announcements for upload progress
👤 Author
Atom Design Team
📄 License
MIT © Atom Design
