diff --git a/index.d.ts b/index.d.ts index db01dc2..4410fe5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -116,6 +116,12 @@ export type SpeechState = { volume: number; }; +export type ClipboardFormats = { + plain?: string; + html?: string; + markdown?: string; +}; + declare module "@uidotdev/usehooks" { export function useBattery(): BatteryManager; @@ -125,9 +131,9 @@ declare module "@uidotdev/usehooks" { export function useCopyToClipboard(): [ string | null, - (value: string) => Promise + (value: string | ClipboardFormats) => void ]; - + export function useCounter( startingValue?: number, options?: { diff --git a/index.js b/index.js index f6e4fe2..a18369a 100644 --- a/index.js +++ b/index.js @@ -145,24 +145,39 @@ export function useCopyToClipboard() { const copyToClipboard = React.useCallback((value) => { const handleCopy = async () => { try { - if (navigator?.clipboard?.writeText) { + // ClipboardItem API for multiple formats + if (typeof value === 'object' && value !== null && window.ClipboardItem) { + const items = {}; + if (value.plain) { + items["text/plain"] = new Blob([value.plain], { type: "text/plain" }); + } + if (value.html) { + items["text/html"] = new Blob([value.html], { type: "text/html" }); + } + if (value.markdown) { + items["text/markdown"] = new Blob([value.markdown], { type: "text/markdown" }); + } + const clipboardItem = new ClipboardItem(items); + await navigator.clipboard.write([clipboardItem]); + setState(value.plain || value.html || value.markdown); + } else if (navigator?.clipboard?.writeText) { await navigator.clipboard.writeText(value); setState(value); } else { throw new Error("writeText not supported"); } } catch (e) { - oldSchoolCopy(value); - setState(value); + oldSchoolCopy(typeof value === 'object' ? value.plain : value); + setState(typeof value === 'object' ? value.plain : value); } }; - handleCopy(); }, []); return [state, copyToClipboard]; } + export function useCounter(startingValue = 0, options = {}) { const { min, max } = options; diff --git a/usehooks.com/src/content/hooks/useCopyToClipboard.mdx b/usehooks.com/src/content/hooks/useCopyToClipboard.mdx index 555fb0c..e7805e8 100644 --- a/usehooks.com/src/content/hooks/useCopyToClipboard.mdx +++ b/usehooks.com/src/content/hooks/useCopyToClipboard.mdx @@ -1,7 +1,7 @@ --- name: useCopyToClipboard rank: 31 -tagline: Copy text to the clipboard using useCopyToClipboard. +tagline: Copy text to the clipboard with support for multiple formats. sandboxId: usecopytoclipboard-y22r6w previewHeight: 300px relatedHooks: @@ -14,12 +14,11 @@ import HookDescription from "../../components/HookDescription.astro"; import StaticCodeContainer from "../../components/StaticCodeContainer.astro"; - The useCopyToClipboard hook is useful because it abstracts the complexity of - copying text to the clipboard in a cross-browser compatible manner. It - utilizes the modern navigator.clipboard.writeText method if available, which - provides a more efficient and secure way to copy text. In case the writeText - method is not supported by the browser, it falls back to a traditional method - using the document.execCommand("copy") approach. + The useCopyToClipboard hook provides a simple way to copy text to the clipboard + with support for multiple clipboard formats. It handles both plain text and rich + content formats, utilizing the modern Clipboard API with fallback support for + older browsers. The hook tracks the copied value and provides error handling + for failed copy operations.
@@ -28,10 +27,12 @@ import StaticCodeContainer from "../../components/StaticCodeContainer.astro"; The `useCopyToClipboard` hook returns an array with the following elements:
+ | Index | Type | Description | | ----- | -------- | ------------------------------------------------------ | - | 0 | string | The value that was last copied to the clipboard. | - | 1 | function | A function to copy a specified value to the clipboard. | + | 0 | object | An object containing `value` (last copied text) and `error` (any error that occurred) | + | 1 | function | A function to copy a specified value to the clipboard. Accepts either a string or an object with `text` and optional `html` properties. | +
@@ -41,7 +42,6 @@ import StaticCodeContainer from "../../components/StaticCodeContainer.astro"; /> - ```jsx import * as React from "react"; import { useCopyToClipboard } from "@uidotdev/usehooks"; @@ -50,38 +50,62 @@ import { copyIcon, checkIcon } from "./icons"; const randomHash = crypto.randomUUID(); export default function App() { - const [copiedText, copyToClipboard] = useCopyToClipboard(); - const hasCopiedText = Boolean(copiedText); + const [{ value, error }, copyToClipboard] = useCopyToClipboard(); + const hasCopiedText = Boolean(value); + + const handleCopyPlainText = () => { + copyToClipboard(randomHash); + }; + + const handleCopyRichText = () => { + copyToClipboard({ + text: randomHash, + html: `API Key: ${randomHash}` + }); + }; + return (

useCopyToClipboard

- +

Fake API Key

-          {randomHash}
+          {randomHash}
           
+          
         
+ {error && ( + +

Error copying to clipboard

+

{error.message}

+
+ )} {hasCopiedText && ( - +

Copied{" "} 🎉

-
)}
); } ``` -