# Copily — Clipboard Tools

A lightweight, TypeScript-first clipboard library. Copy and paste text, HTML, JSON, images, and files. Intercept copy/paste events and perform smart clipboard detection.

## Features

- **Basic Copy & Paste**: Text, HTML, JSON, images, and files
- **Smart Detection**: Detect OTP, URL, email, JSON, HTML, image, and file
- **Copy Interception**: Intercept and modify copy events
- **Paste Interception**: Intercept and override paste behavior
- **Smart Paste Listener**: Listen to paste events with smart detection
- **Security**: HTML sanitization and secure-context checks
- **Fallbacks**: Legacy support via `document.execCommand`

## Installation

```bash
npm install @mirawision/copily
```

## Quick Start

```typescript
// Root import (all core + advanced)
import { copyText, pasteText, pasteSmart } from '@mirawision/copily';

await copyText('Hello Copily!');
const results = await pasteSmart();
```

```typescript
// Subpath imports (tree-shakable)
import { copyText, pasteHTML } from '@mirawision/copily/core';
import { pasteSmart, interceptPaste } from '@mirawision/copily/advanced';
```

## API Reference

### Basic Copy & Paste

#### `copyText(text: string): Promise<void>`
Copies plain text to clipboard.

```typescript
await copyText('Hello World!');
```

#### `pasteText(): Promise<string>`
Reads plain text from clipboard.

```typescript
const text = await pasteText();
console.log(text); // "Hello World!"
```

#### `copyHTML(html: string): Promise<void>`
Copies HTML content with fallback plain text.

```typescript
await copyHTML('<p>Hello <strong>World</strong>!</p>');
```

#### `pasteHTML(): Promise<string>`
Reads HTML content from clipboard.

```typescript
const html = await pasteHTML();
console.log(html); // "<p>Hello <strong>World</strong>!</p>"
```

#### `copyJSON(obj: object): Promise<void>`
Serializes object to JSON and copies to clipboard.

```typescript
await copyJSON({ name: 'John', age: 30 });
```

#### `pasteJSON(): Promise<object>`
Parses clipboard content as JSON.

```typescript
const data = await pasteJSON();
console.log(data); // { name: 'John', age: 30 }
```

### Files & Images

#### `copyImage(image: Blob | HTMLImageElement | string): Promise<void>`
Copies image to clipboard from blob, element, or URL.

```typescript
// From blob
const imageBlob = new Blob(['image data'], { type: 'image/png' });
await copyImage(imageBlob);

// From URL
await copyImage('https://example.com/image.jpg');

// From HTML element
const img = document.querySelector('img');
await copyImage(img);
```

#### `pasteImage(): Promise<Blob | null>`
Reads image from clipboard.

```typescript
const imageBlob = await pasteImage();
if (imageBlob) {
  const url = URL.createObjectURL(imageBlob);
  // Use the image URL
}
```

#### `copyFile(file: File | Blob): Promise<void>`
Copies file to clipboard.

```typescript
const file = new File(['file content'], 'document.txt', { type: 'text/plain' });
await copyFile(file);
```

#### `pasteFile(): Promise<File | null>`
Reads file from clipboard.

```typescript
const file = await pasteFile();
if (file) {
  console.log(file.name); // "clipboard-file"
}
```

### Smart Detection

#### `pasteSmart(): Promise<ClipboardSmartResult[]>`
Intelligently detects clipboard content and returns structured results.

```typescript
const results = await pasteSmart();

// Results can include:
// { type: 'otp', value: '123456' }
// { type: 'url', value: 'https://example.com' }
// { type: 'email', value: 'user@example.com' }
// { type: 'json', value: { name: 'John' } }
// { type: 'html', value: '<p>content</p>' }
// { type: 'text', value: 'plain text' }
// { type: 'image', blob: Blob }
// { type: 'file', file: File }
```

### Clipboard Event Utilities

#### `interceptCopy(handler: CopyInterceptHandler): () => void`
Intercepts copy events on the page.

```typescript
const cleanup = interceptCopy(({ event, selection, target }) => {
  // Block copying from private elements
  if (target?.classList.contains('private')) {
    return { prevent: true };
  }
  
  // Add attribution
  return {
    overrideText: `${selection}\n\nCopied from mysite.com`,
    overrideHTML: `${selection}<br><br><em>Copied from mysite.com</em>`
  };
});

// Cleanup when done
cleanup();
```

#### `interceptPaste(handler: PasteInterceptHandler): () => void`
Intercepts paste events on the page with optional overrides.

```typescript
const cleanup = interceptPaste(({ event, plainText, html, target }) => {
  // Force plain text only
  return { overrideText: plainText };
  // Or block entirely: return { prevent: true };
  // Or inject HTML into contenteditable: return { overrideHTML: '<strong>Pasted</strong>' };
});

cleanup();
```

#### `listenCopy(callback: (params: { event: ClipboardEvent; selection: string; target: HTMLElement | null }) => void): () => void`
Listens to copy events and provides selection details.

```typescript
const cleanup = listenCopy(({ event, selection, target }) => {
  if (!selection) return;
  console.log('Copied:', selection);
});

cleanup();
```

#### `listenPaste(callback: (data: ClipboardSmartResult[]) => void): () => void`
Listens to paste events with smart detection.

```typescript
const cleanup = listenPaste((results) => {
  results.forEach(result => {
    switch (result.type) {
      case 'otp':
        console.log('OTP detected:', result.value);
        break;
      case 'url':
        console.log('URL detected:', result.value);
        break;
      case 'email':
        console.log('Email detected:', result.value);
        break;
    }
  });
});

// Cleanup when done
cleanup();
```

### Extras & Fallbacks

#### `clearClipboard(): Promise<void>`
Clears clipboard content.

```typescript
await clearClipboard();
```

#### `fallbackCopyText(text: string): void`
Legacy copy using `document.execCommand`.

```typescript
try {
  await copyText('Hello');
} catch {
  fallbackCopyText('Hello');
}
```

## Error Handling

The library provides specific error types for different scenarios:

```typescript
import { 
  ClipboardError,
  ClipboardPermissionError,
  ClipboardUnsupportedError,
  ClipboardFormatError 
} from '@mirawision/copily';

try {
  await copyText('Hello');
} catch (error) {
  if (error instanceof ClipboardPermissionError) {
    // Handle permission denied
  } else if (error instanceof ClipboardUnsupportedError) {
    // Handle unsupported browser
  } else if (error instanceof ClipboardFormatError) {
    // Handle format errors
  }
}
```

## Security & Permissions

### Secure Context & Permissions
- The Clipboard API requires HTTPS. Operations will fail with a `ClipboardPermissionError` if not secure.
- Permission prompts are handled by the browser. Catch errors to provide UX fallbacks.

### HTML Sanitization
HTML content is automatically sanitized to prevent XSS:

```typescript
// This will be sanitized automatically
await copyHTML('<script>alert("xss")</script><p>Safe content</p>');
// Result: <p>Safe content</p>
```

## Browser Support

- **Modern Browsers**: Full support with Clipboard API
- **Older Browsers**: Fallback support with `document.execCommand`
- **Mobile**: Limited support (varies by platform)

## Use Cases

### Copy with Attribution
```typescript
interceptCopy(({ selection }) => ({
  overrideText: `${selection}\n\nCopied from mysite.com`,
  overrideHTML: `${selection}<br><br><em>Copied from mysite.com</em>`
}));
```

### OTP Code Detection
```typescript
listenPaste((results) => {
  const otp = results.find(r => r.type === 'otp');
  if (otp) {
    // Auto-fill OTP input
    document.getElementById('otp-input').value = otp.value;
  }
});
```

### Rich Text Copy
```typescript
// Use HTML + styles when needed
await copyHTML('<span style="font-weight:700;color:#f00;font-size:18px">Important notice</span>');
```

### Image Processing
```typescript
const imageBlob = await pasteImage();
if (imageBlob) {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const img = new Image();
  img.onload = () => {
    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage(img, 0, 0);
    // Process the image
  };
  img.src = URL.createObjectURL(imageBlob);
}
```

## Contributing

Contributions are always welcome! Feel free to open issues or submit pull requests.

## License

This project is licensed under the MIT License.
