copy-chip.tsx36 lines · main
1'use client';
2
3import { useState } from 'react';
4
5import { CopyIcon } from './animated-icons';
6
7/**
8 * Bare copy-to-clipboard icon button for inline use next to a value that
9 * is rendered elsewhere (unlike CopyField, which owns its own input).
10 * On click the copy glyph morphs into the checkmark for ~1.5s.
11 */
12export function CopyChip({ value, label }: { value: string; label?: string }) {
13 const [copied, setCopied] = useState(false);
14
15 async function copy() {
16 try {
17 await navigator.clipboard.writeText(value);
18 } catch {
19 // Clipboard API can be unavailable on insecure contexts; nothing to
20 // fall back to here since the value isn't in an input we own.
21 }
22 setCopied(true);
23 setTimeout(() => setCopied(false), 1500);
24 }
25
26 return (
27 <button
28 type="button"
29 onClick={copy}
30 aria-label={copied ? 'copied' : `copy ${label ?? 'value'} to clipboard`}
31 className="flex size-7 shrink-0 items-center justify-center rounded border border-[var(--color-border-subtle)] text-[var(--color-text-muted)] transition-colors hover:border-[var(--color-border)] hover:text-[var(--color-primary)]"
32 >
33 <CopyIcon className="size-3.5" copied={copied} />
34 </button>
35 );
36}