😄
Reactとshadcnでコピーボタンを作る
Reactとshadcnでコピーボタンを作る。
ChatGPTやClaudeなどでよく見かけるボタンをクリックすると、コードをコピーできるボタンを作る。
実装例
結論としては汚いコードにはなるが、以下のようになる。
TooltipTrigger
配下のbuttonタグに
onMouseOver={() => setOpen(true)}
,
onMouseLeave={() => setOpen(false)}
を指定している理由は、クリックすると、ツールチップが消えてしまうので、マウスカーソルをボタンから外さない限り、ツールチップが表示されるようにしています。
import { useState } from "react";
import { CircleCheckIcon, ClipboardIcon } from "lucide-react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/utils/cn";
interface Props extends React.ComponentProps<"button"> {
copyText?: string;
}
export const CopyButton = (props: Props) => {
const { copyText = "", className, ...args } = props;
const [isCopied, setCopied] = useState<boolean>(false);
const [open, setOpen] = useState<boolean>(false);
const handleClick = async () => {
setCopied(false);
await global.navigator.clipboard.writeText(copyText);
setTimeout(() => {
setCopied(true);
}, 2000);
};
return (
<TooltipProvider>
<Tooltip defaultOpen={false} open={open}>
<TooltipTrigger asChild>
<button
{...args}
className={cn("size-6 flex justify-center items-center", className)}
onClick={() => !isCopied && handleClick()}
onMouseOver={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
>
{isCopied ? (
<CircleCheckIcon className={"size-full"} />
) : (
<ClipboardIcon className={"size-full"} />
)}
</button>
</TooltipTrigger>
{open && (
<TooltipContent>
{isCopied ? "コピーしました" : "コピー"}
</TooltipContent>
)}
</Tooltip>
</TooltipProvider>
);
};
実際のコピーしている処理は以下の部分。
async, await
、およびglobal
がないと正常に動作しないので、忘れず書く
const handleClick = async () => {
setCopied(copied);
await global.navigator.clipboard.writeText(copyText);
setTimeout(() => {
setCopied(!copied);
}, 2000);
};
最後に
コードやER図など間違っていることがあれば、コメントに書いていただけると幸いです。
よろしくお願いいたします。
Discussion