Files
kavinkasper a4899494e7 fix: add missing tooltip support to action buttons (#254)
* fix: add missing title attributes to action buttons for accessibility

* Create vast-cameras-move.md

---------

Co-authored-by: kavin kumar <kavin.kumar@agilepoint.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
2025-11-24 09:46:17 -08:00

81 lines
1.9 KiB
TypeScript

import { CheckIcon, CopyIcon } from "lucide-react";
import {
type ComponentProps,
useContext,
useEffect,
useRef,
useState,
} from "react";
import { StreamdownContext } from "../../index";
import { cn } from "../utils";
import { useCodeBlockContext } from "./context";
export type CodeBlockCopyButtonProps = ComponentProps<"button"> & {
onCopy?: () => void;
onError?: (error: Error) => void;
timeout?: number;
};
export const CodeBlockCopyButton = ({
onCopy,
onError,
timeout = 2000,
children,
className,
code: propCode,
...props
}: CodeBlockCopyButtonProps & { code?: string }) => {
const [isCopied, setIsCopied] = useState(false);
const timeoutRef = useRef(0);
const { code: contextCode } = useCodeBlockContext();
const { isAnimating } = useContext(StreamdownContext);
const code = propCode ?? contextCode;
const copyToClipboard = async () => {
if (typeof window === "undefined" || !navigator?.clipboard?.writeText) {
onError?.(new Error("Clipboard API not available"));
return;
}
try {
if (!isCopied) {
await navigator.clipboard.writeText(code);
setIsCopied(true);
onCopy?.();
timeoutRef.current = window.setTimeout(
() => setIsCopied(false),
timeout
);
}
} catch (error) {
onError?.(error as Error);
}
};
useEffect(
() => () => {
window.clearTimeout(timeoutRef.current);
},
[]
);
const Icon = isCopied ? CheckIcon : CopyIcon;
return (
<button
className={cn(
"cursor-pointer p-1 text-muted-foreground transition-all hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50",
className
)}
data-streamdown="code-block-copy-button"
disabled={isAnimating}
onClick={copyToClipboard}
title="Copy Code"
type="button"
{...props}
>
{children ?? <Icon size={14} />}
</button>
);
};