All files / web/src/hooks useClipboard.ts

100% Statements 68/68
100% Branches 6/6
100% Functions 1/1
100% Lines 68/68

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 691x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 67x 67x 67x 67x 67x 15x 15x 13x 13x 2x 13x 13x 15x 2x 2x 2x 15x 67x 67x 67x 67x 8x 67x 67x 67x 67x  
import { useCallback, useState } from 'react'
 
export interface UseClipboardOptions {
  /**
   * Timeout in milliseconds to reset the copied state
   * @default 1500
   */
  timeout?: number
}
 
export interface UseClipboardReturn {
  /**
   * Whether the text was recently copied
   */
  copied: boolean
 
  /**
   * Copy text to clipboard. Resolves true on success, false when the
   * clipboard refused (permissions, insecure context) — callers that need a
   * fallback affordance branch on it; existing callers ignore it.
   */
  copy: (text: string) => Promise<boolean>
 
  /**
   * Reset the copied state manually
   */
  reset: () => void
}
 
/**
 * Hook for copying text to clipboard with visual feedback
 *
 * @example
 * ```tsx
 * const { copied, copy } = useClipboard()
 *
 * <button onClick={() => copy('Hello!')}>
 *   {copied ? 'Copied!' : 'Copy'}
 * </button>
 * ```
 */
export function useClipboard(options: UseClipboardOptions = {}): UseClipboardReturn {
  const { timeout = 1500 } = options
  const [copied, setCopied] = useState(false)
 
  const copy = useCallback(
    async (text: string) => {
      try {
        await navigator.clipboard.writeText(text)
        setCopied(true)
        setTimeout(() => {
          setCopied(false)
        }, timeout)
        return true
      } catch (error) {
        console.error('[useClipboard] Failed to copy to clipboard:', error)
        return false
      }
    },
    [timeout]
  )
 
  const reset = useCallback(() => {
    setCopied(false)
  }, [])
 
  return { copied, copy, reset }
}