61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
import { Slot } from "@radix-ui/react-slot";
|
|
import { cn } from "@/lib/utils";
|
|
import { ReactNode } from "react";
|
|
|
|
type ButtonProps = {
|
|
variant?: "primary" | "secondary" | "success" | "warning" | "danger" | "muted" | "info";
|
|
size?: "sm" | "md" | "lg";
|
|
asChild?: boolean;
|
|
children: ReactNode;
|
|
isLoading?: boolean;
|
|
icon?: ReactNode; // ← ★ アイコン追加
|
|
iconPosition?: "left" | "right"; // ← ★ 位置も制御可能
|
|
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
|
|
|
|
export function Button({
|
|
variant = "primary",
|
|
size = "md",
|
|
asChild,
|
|
children,
|
|
isLoading,
|
|
icon,
|
|
iconPosition = "left",
|
|
className,
|
|
...props
|
|
}: ButtonProps) {
|
|
const Comp = asChild ? Slot : "button";
|
|
|
|
return (
|
|
<Comp
|
|
className={cn(
|
|
"inline-flex items-center justify-center gap-2 font-medium rounded-lg transition whitespace-nowrap disabled:opacity-50 disabled:pointer-events-none",
|
|
{
|
|
"bg-sky-500 hover:bg-sky-600 text-white shadow": variant === "primary",
|
|
"bg-gray-300 hover:bg-gray-400 text-gray-700": variant === "secondary",
|
|
"bg-green-500 hover:bg-green-600 text-white shadow": variant === "success",
|
|
"bg-orange-500 hover:bg-orange-600 text-white shadow": variant === "warning",
|
|
"bg-red-600 hover:bg-red-700 text-white shadow": variant === "danger",
|
|
"bg-purple-200 hover:bg-purple-300 text-gray-400": variant === "muted",
|
|
"bg-sky-400 hover:bg-sky-500 text-gray-50 shadow": variant === "info",
|
|
},
|
|
{
|
|
"w-[110px] h-[36px] px-3 text-sm": size === "sm",
|
|
"w-[140px] h-[42px] px-4 text-base": size === "md",
|
|
"w-[180px] h-[48px] px-6 text-base font-semibold": size === "lg",
|
|
},
|
|
className
|
|
)}
|
|
{...props}
|
|
>
|
|
<span className="flex items-center justify-center gap-2">
|
|
{isLoading && (
|
|
<span className="inline-block w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
|
)}
|
|
{!isLoading && icon && iconPosition === "left" && <span>{icon}</span>}
|
|
<span>{children}</span>
|
|
{!isLoading && icon && iconPosition === "right" && <span>{icon}</span>}
|
|
</span>
|
|
</Comp>
|
|
);
|
|
}
|