@mirawision/copily
Version:
A comprehensive clipboard manipulation library for TypeScript, providing functionalities for copying/pasting text, HTML, JSON, images, files, and smart content detection.
342 lines (265 loc) • 8.36 kB
Markdown
A lightweight, TypeScript-first clipboard library. Copy and paste text, HTML, JSON, images, and files. Intercept copy/paste events and perform smart clipboard detection.
- **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`
```bash
npm install @mirawision/copily
```
```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';
```
Copies plain text to clipboard.
```typescript
await copyText('Hello World!');
```
Reads plain text from clipboard.
```typescript
const text = await pasteText();
console.log(text); // "Hello World!"
```
Copies HTML content with fallback plain text.
```typescript
await copyHTML('<p>Hello <strong>World</strong>!</p>');
```
Reads HTML content from clipboard.
```typescript
const html = await pasteHTML();
console.log(html); // "<p>Hello <strong>World</strong>!</p>"
```
Serializes object to JSON and copies to clipboard.
```typescript
await copyJSON({ name: 'John', age: 30 });
```
Parses clipboard content as JSON.
```typescript
const data = await pasteJSON();
console.log(data); // { name: 'John', age: 30 }
```
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);
```
Reads image from clipboard.
```typescript
const imageBlob = await pasteImage();
if (imageBlob) {
const url = URL.createObjectURL(imageBlob);
// Use the image URL
}
```
Copies file to clipboard.
```typescript
const file = new File(['file content'], 'document.txt', { type: 'text/plain' });
await copyFile(file);
```
Reads file from clipboard.
```typescript
const file = await pasteFile();
if (file) {
console.log(file.name); // "clipboard-file"
}
```
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 }
```
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();
```
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();
```
Listens to copy events and provides selection details.
```typescript
const cleanup = listenCopy(({ event, selection, target }) => {
if (!selection) return;
console.log('Copied:', selection);
});
cleanup();
```
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();
```
Clears clipboard content.
```typescript
await clearClipboard();
```
Legacy copy using `document.execCommand`.
```typescript
try {
await copyText('Hello');
} catch {
fallbackCopyText('Hello');
}
```
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
}
}
```
- 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 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>
```
- **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>`
}));
```
```typescript
listenPaste((results) => {
const otp = results.find(r => r.type === 'otp');
if (otp) {
// Auto-fill OTP input
document.getElementById('otp-input').value = otp.value;
}
});
```
```typescript
// Use HTML + styles when needed
await copyHTML('<span style="font-weight:700;color:#f00;font-size:18px">Important notice</span>');
```
```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);
}
```
Contributions are always welcome! Feel free to open issues or submit pull requests.
This project is licensed under the MIT License.