Files
CodeNomad/packages/ui/src/lib/clipboard.ts
bizzkoot 3c450c076a fix: copy button functionality in web browsers
- Add clipboard utility with fallback for non-secure contexts
- Implement modern Clipboard API with document.execCommand fallback
- Update copy buttons in code blocks, markdown, messages, and session list
- Add proper error handling and user feedback for copy operations

Fixes issue where copy buttons did not work in web browsers served over HTTP or without Clipboard API support
2026-01-04 20:00:22 +08:00

61 lines
1.8 KiB
TypeScript

/**
* Clipboard utility with fallback for non-secure contexts
* The modern Clipboard API requires HTTPS or localhost, but document.execCommand
* works in HTTP contexts as a fallback.
*/
import { getLogger } from "./logger"
const log = getLogger("actions")
/**
* Copy text to clipboard with fallback for non-secure contexts
* @param text - The text to copy
* @returns Promise<boolean> - true if successful, false if failed
*/
export async function copyToClipboard(text: string): Promise<boolean> {
try {
// Try modern Clipboard API first (requires secure context)
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(text)
log.info("Copied text using Clipboard API")
return true
}
} catch (error) {
log.warn("Clipboard API failed, trying fallback:", error)
}
// Fallback for non-secure contexts (HTTP) using document.execCommand
try {
if (typeof document === "undefined") {
log.error("Document not available for clipboard fallback")
return false
}
// Create temporary textarea element
const textArea = document.createElement("textarea")
textArea.value = text
textArea.style.position = "fixed"
textArea.style.left = "-9999px"
textArea.style.top = "-9999px"
textArea.style.opacity = "0"
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
const success = document.execCommand("copy")
document.body.removeChild(textArea)
if (success) {
log.info("Copied text using execCommand fallback")
return true
} else {
log.error("execCommand copy failed")
return false
}
} catch (error) {
log.error("Clipboard fallback failed:", error)
return false
}
}