UNPKG

@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
# 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.