Pulse/frontend-modern/src/components/shared/CopyButton.tsx
2025-10-11 23:29:47 +00:00

88 lines
2.7 KiB
TypeScript

import { createSignal, onCleanup, splitProps } from 'solid-js';
import type { JSX } from 'solid-js';
interface CopyButtonProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
text: string;
children: JSX.Element;
}
export function CopyButton(props: CopyButtonProps) {
const [local, others] = splitProps(props, ['text', 'children', 'class', 'onClick']);
const [copied, setCopied] = createSignal(false);
let resetTimeout: number | undefined;
const handleClick = async (event: MouseEvent) => {
const handler = local.onClick as
| ((event: MouseEvent) => void)
| { handleEvent?: (event: MouseEvent) => void }
| undefined;
if (typeof handler === 'function') {
handler(event);
} else if (handler && typeof handler.handleEvent === 'function') {
handler.handleEvent(event);
}
if (event.defaultPrevented) {
return;
}
try {
await navigator.clipboard.writeText(local.text);
setCopied(true);
window.clearTimeout(resetTimeout);
resetTimeout = window.setTimeout(() => setCopied(false), 2000);
} catch (error) {
console.error('Failed to copy to clipboard', error);
}
};
onCleanup(() => {
if (resetTimeout) {
window.clearTimeout(resetTimeout);
}
});
return (
<button
type="button"
{...others}
onClick={handleClick}
class={`inline-flex items-center justify-center gap-2 rounded-md border border-transparent bg-blue-600 px-4 py-2 text-xs sm:text-sm font-medium text-white shadow-sm transition-colors hover:bg-blue-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-400 ${
local.class ?? ''
}`}
>
{copied() ? (
<>
<svg
class="h-4 w-4"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M16.707 5.293a1 1 0 00-1.414 0L8 12.586 4.707 9.293a1 1 0 00-1.414 1.414l4 4a1 1 0 001.414 0l8-8a1 1 0 000-1.414z"
clip-rule="evenodd"
/>
</svg>
<span>Copied</span>
</>
) : (
<>
<svg
class="h-4 w-4"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path d="M8 2a2 2 0 00-2 2v1H5a3 3 0 00-3 3v7a3 3 0 003 3h6a3 3 0 003-3v-1h1a2 2 0 002-2V7.414a2 2 0 00-.586-1.414l-3.414-3.414A2 2 0 0013.586 2H8zm4 4V3.414L15.586 7H13a1 1 0 01-1-1z" />
<path d="M3 8a1 1 0 011-1h6a1 1 0 011 1v7a1 1 0 01-1 1H4a1 1 0 01-1-1V8z" />
</svg>
<span>{local.children}</span>
</>
)}
</button>
);
}
export default CopyButton;