npm package: @fivexlabs/use-file-system
Description: A comprehensive React hook for the File System Access API with TypeScript support
Author: Fivex Labs
Latest version: 1.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.

[![npm version](https://badge.fury.io/js/@fivexlabs%2Fuse-file-system.svg)](https://badge.fury.io/js/@fivexlabs%2Fuse-file-system)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](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**