@fivexlabs/use-file-system
Version:
A comprehensive React hook for the File System Access API with TypeScript support
370 lines (295 loc) • 9.48 kB
Markdown
# 🗂️ useFileSystem Hook
A comprehensive React hook for the **File System Access API** with full TypeScript support. Simplify modern file system interactions in your React applications with a clean, intuitive API.
[](https://badge.fury.io/js/@fivexlabs%2Fuse-file-system)
[](https://opensource.org/licenses/MIT)
[](http://www.typescriptlang.org/)
## ✨ Features
- 🔍 **Browser Compatibility Check** - Automatically detects File System Access API support
- 📁 **File Operations** - Open single or multiple files with type filtering
- 💾 **Save Operations** - Save files with custom names and formats
- 📂 **Directory Access** - Open and interact with directories
- 🏗️ **State Management** - Built-in loading, error, and data states
- 🛡️ **Error Handling** - Graceful error handling with detailed error states
- 📘 **TypeScript Support** - Full type definitions included
- ⚡ **Modern API** - Built on the latest File System Access API
- 🎣 **React Hooks** - Follows React hooks patterns and best practices
## 🚀 Installation
```bash
npm install @fivexlabs/use-file-system
```
```bash
yarn add @fivexlabs/use-file-system
```
```bash
pnpm add @fivexlabs/use-file-system
```
## 🌐 Browser Support
The File System Access API is currently supported in:
- **Chrome** 86+
- **Edge** 86+
- **Opera** 72+
> **Note:** This API is not yet supported in Firefox or Safari. The hook includes built-in browser compatibility detection.
## 📖 Basic Usage
```jsx
import React from 'react';
import { useFileSystem } from '@fivexlabs/use-file-system';
function MyComponent() {
const {
isSupported,
file,
loading,
error,
openFile,
saveAs,
clearError
} = useFileSystem();
const handleOpenFile = async () => {
try {
await openFile({
types: [{
description: 'Text files',
accept: {
'text/plain': ['.txt'],
'text/markdown': ['.md']
}
}]
});
} catch (err) {
console.error('Failed to open file:', err);
}
};
const handleSaveFile = async () => {
const content = 'Hello, World!';
try {
await saveAs(content, 'hello.txt');
} catch (err) {
console.error('Failed to save file:', err);
}
};
if (!isSupported) {
return <div>File System Access API is not supported in this browser.</div>;
}
return (
<div>
{error && (
<div style={{ color: 'red' }}>
Error: {error.message}
<button onClick={clearError}>Clear</button>
</div>
)}
{loading && <div>Loading...</div>}
<button onClick={handleOpenFile} disabled={loading}>
Open File
</button>
<button onClick={handleSaveFile} disabled={loading}>
Save File
</button>
{file && (
<div>
<h3>Selected File:</h3>
<p><strong>Name:</strong> {file.name}</p>
<p><strong>Size:</strong> {file.size} bytes</p>
<p><strong>Type:</strong> {file.type}</p>
{file.content && (
<pre>{String(file.content).slice(0, 200)}...</pre>
)}
</div>
)}
</div>
);
}
```
## 📚 API Reference
### Hook Return Value
The `useFileSystem` hook returns an object with the following properties:
#### State Properties
| Property | Type | Description |
|----------|------|-------------|
| `isSupported` | `boolean` | Whether the File System Access API is supported |
| `file` | `FileDetails \| null` | Currently selected single file |
| `files` | `FileDetails[]` | Array of selected multiple files |
| `directory` | `DirectoryDetails \| null` | Currently selected directory |
| `loading` | `boolean` | Loading state for async operations |
| `error` | `Error \| null` | Current error state |
#### Action Methods
| Method | Parameters | Description |
|--------|------------|-------------|
| `openFile` | `options?: OpenFilePickerOptions` | Open a single file |
| `openMultipleFiles` | `options?: OpenFilePickerOptions` | Open multiple files |
| `saveFile` | `suggestedName: string, data: BlobPart[], options?: SaveFilePickerOptions` | Save data to a file |
| `saveAs` | `content: string \| ArrayBuffer, suggestedName?: string, options?: SaveFilePickerOptions` | Save content with a suggested name |
| `openDirectory` | `options?: DirectoryPickerOptions` | Open a directory |
| `readFileContent` | `file: File, readAs?: 'text' \| 'buffer'` | Read file content as text or buffer |
#### Clear Methods
| Method | Description |
|--------|-------------|
| `clearFile()` | Clear the current file |
| `clearFiles()` | Clear all selected files |
| `clearDirectory()` | Clear the selected directory |
| `clearError()` | Clear the current error |
### Type Definitions
```typescript
interface FileDetails {
name: string;
content: string | ArrayBuffer | null;
handle: FileSystemFileHandle | null;
size: number;
type: string;
lastModified: number;
}
interface DirectoryDetails {
name: string;
handle: FileSystemDirectoryHandle | null;
}
```
## 🎯 Advanced Examples
### Opening Multiple Files with Type Filtering
```jsx
const handleOpenImages = async () => {
try {
await openMultipleFiles({
types: [{
description: 'Images',
accept: {
'image/*': ['.png', '.jpg', '.jpeg', '.gif', '.webp']
}
}]
});
} catch (err) {
console.error('Failed to open images:', err);
}
};
```
### Saving JSON Data
```jsx
const handleSaveJSON = async () => {
const data = { message: 'Hello', timestamp: Date.now() };
try {
await saveAs(
JSON.stringify(data, null, 2),
'data.json',
{
types: [{
description: 'JSON files',
accept: {
'application/json': ['.json']
}
}]
}
);
} catch (err) {
console.error('Failed to save JSON:', err);
}
};
```
### Working with Directories
```jsx
const handleOpenDirectory = async () => {
try {
await openDirectory({ mode: 'readwrite' });
// Now you can access directory.handle for further operations
} catch (err) {
console.error('Failed to open directory:', err);
}
};
```
### Reading File Content as ArrayBuffer
```jsx
const handleOpenBinaryFile = async () => {
try {
const input = document.createElement('input');
input.type = 'file';
input.onchange = async (e) => {
const file = e.target.files[0];
if (file) {
const buffer = await readFileContent(file, 'buffer');
console.log('File buffer:', buffer);
}
};
input.click();
} catch (err) {
console.error('Failed to read file:', err);
}
};
```
## 🔧 Configuration Options
### OpenFilePickerOptions
```typescript
interface OpenFilePickerOptions {
multiple?: boolean;
excludeAcceptAllOption?: boolean;
types?: FilePickerAcceptType[];
}
```
### SaveFilePickerOptions
```typescript
interface SaveFilePickerOptions {
suggestedName?: string;
excludeAcceptAllOption?: boolean;
types?: FilePickerAcceptType[];
}
```
### DirectoryPickerOptions
```typescript
interface DirectoryPickerOptions {
mode?: 'read' | 'readwrite';
}
```
### FilePickerAcceptType
```typescript
interface FilePickerAcceptType {
description?: string;
accept: Record<string, string | string[]>;
}
```
## 🛡️ Error Handling
The hook provides comprehensive error handling:
```jsx
const { error, clearError } = useFileSystem();
// Handle different types of errors
if (error) {
if (error.name === 'AbortError') {
// User cancelled the operation
console.log('Operation was cancelled');
} else if (error.name === 'NotAllowedError') {
// Permission denied
console.log('Permission denied');
} else {
// Other errors
console.log('An error occurred:', error.message);
}
}
```
## 🎨 Demo Application
This repository includes a comprehensive demo application showcasing all features. To run the demo:
```bash
git clone https://github.com/fivex-labs/use-file-system.git
cd use-file-system
npm install
npm run dev
```
## 🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
### Development Setup
```bash
git clone https://github.com/fivex-labs/use-file-system.git
cd use-file-system
npm install
```
### Available Scripts
- `npm run dev` - Start the demo application
- `npm run build` - Build the demo application
- `npm run build:lib` - Build the library for distribution
- `npm run lint` - Run ESLint
## 📜 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## 🙏 Acknowledgments
- Built with ❤️ by [Fivex Labs](https://github.com/fivex-labs)
- Inspired by the modern web's File System Access API
- Thanks to the React community for hooks patterns and best practices
## 🔗 Links
- [File System Access API Documentation](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API)
- [Browser Compatibility](https://caniuse.com/native-filesystem-api)
- [Demo Application](https://use-file-system-demo.netlify.app)
---
**Made with ❤️ [by Fivex Labs](https://fivexlabs.com) for the developer community**