blob: 0e22e9471f7a427e7645ecec9f38322a53a98b05 [file]
"use client";
import React from "react";
import { cn } from "@/ui/lib/utils";
export interface IconButtonRootProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
disabled?: boolean;
variant?:
| "brand-primary"
| "brand-secondary"
| "brand-tertiary"
| "neutral-primary"
| "neutral-secondary"
| "neutral-tertiary"
| "destructive-primary"
| "destructive-secondary"
| "destructive-tertiary"
| "inverse";
size?: "large" | "medium" | "small";
icon?: React.ReactNode;
loading?: boolean;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
className?: string;
}
function Spinner({ className }: { className?: string }) {
return (
<svg viewBox="0 0 24 24" className={cn("size-4 animate-spin", className)} aria-hidden="true">
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="3"
strokeDasharray="40 60"
fill="none"
strokeLinecap="round"
/>
</svg>
);
}
const IconButtonRoot = React.forwardRef<HTMLButtonElement, IconButtonRootProps>(
function IconButtonRoot(
{
disabled = false,
variant = "neutral-tertiary",
size = "medium",
icon = null,
loading = false,
className,
type = "button",
...otherProps
}: IconButtonRootProps,
ref
) {
const iconColor = cn(
"text-heading-3 font-heading-3 text-neutral-700 group-disabled:text-neutral-400",
{
"text-body font-body": size === "small",
"text-white":
variant === "inverse" ||
variant === "destructive-primary" ||
variant === "brand-primary",
"text-error-700":
variant === "destructive-tertiary" || variant === "destructive-secondary",
"text-brand-700":
variant === "brand-tertiary" || variant === "brand-secondary",
}
);
return (
<button
className={cn(
"group flex h-8 w-8 cursor-pointer items-center justify-center gap-2 rounded-md border-none bg-transparent text-left hover:bg-neutral-100 active:bg-neutral-50 disabled:cursor-default disabled:bg-neutral-100",
{
"h-6 w-6": size === "small",
"h-10 w-10": size === "large",
"hover:bg-[#ffffff29] active:bg-[#ffffff3d]": variant === "inverse",
"hover:bg-error-50 active:bg-error-100": variant === "destructive-tertiary",
"bg-error-50 hover:bg-error-100 active:bg-error-50":
variant === "destructive-secondary",
"bg-error-600 hover:bg-error-500 active:bg-error-600":
variant === "destructive-primary",
"border border-solid border-neutral-border bg-white active:bg-white":
variant === "neutral-secondary",
"bg-neutral-100 hover:bg-neutral-200 active:bg-neutral-100":
variant === "neutral-primary",
"hover:bg-brand-50 active:bg-brand-100": variant === "brand-tertiary",
"bg-brand-50 hover:bg-brand-100 active:bg-brand-50": variant === "brand-secondary",
"bg-brand-600 hover:bg-brand-500 active:bg-brand-600": variant === "brand-primary",
},
className
)}
ref={ref}
type={type}
disabled={disabled}
{...otherProps}
>
{loading ? (
<Spinner className={iconColor} />
) : icon ? (
<span className={cn("inline-flex items-center [&_svg]:size-4", iconColor)}>
{icon}
</span>
) : null}
</button>
);
}
);
export const IconButton = IconButtonRoot;