@fivexlabs/use-file-system v1.0.0
🗂️ 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.
✨ 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
npm install @fivexlabs/use-file-systemyarn add @fivexlabs/use-file-systempnpm 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
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
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
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
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
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
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
interface OpenFilePickerOptions {
multiple?: boolean;
excludeAcceptAllOption?: boolean;
types?: FilePickerAcceptType[];
}SaveFilePickerOptions
interface SaveFilePickerOptions {
suggestedName?: string;
excludeAcceptAllOption?: boolean;
types?: FilePickerAcceptType[];
}DirectoryPickerOptions
interface DirectoryPickerOptions {
mode?: 'read' | 'readwrite';
}FilePickerAcceptType
interface FilePickerAcceptType {
description?: string;
accept: Record<string, string | string[]>;
}🛡️ Error Handling
The hook provides comprehensive error handling:
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:
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
git clone https://github.com/fivex-labs/use-file-system.git
cd use-file-system
npm installAvailable Scripts
npm run dev- Start the demo applicationnpm run build- Build the demo applicationnpm run build:lib- Build the library for distributionnpm run lint- Run ESLint
📜 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with ❤️ by Fivex Labs
- Inspired by the modern web's File System Access API
- Thanks to the React community for hooks patterns and best practices
🔗 Links
Made with ❤️ by Fivex Labs for the developer community
6 months ago