shoc-frontend-new/src/components/ui/button.tsx

70 lines
1.9 KiB
TypeScript

import type { ButtonProps } from "@mui/material";
import { Button as MuiButton, CircularProgress } from "@mui/material";
import { cn } from "@/lib/utils";
type ButtonVariant = "default" | "destructive" | "outline" | "ghost" | "link";
type ButtonSize = "default" | "lg";
export type UiButtonProps = Omit<ButtonProps, "variant" | "color" | "size"> & {
variant?: ButtonVariant;
size?: ButtonSize;
loading?: boolean;
loadingText?: string;
};
const variantMap: Record<
ButtonVariant,
Pick<ButtonProps, "variant" | "color"> & { className?: string }
> = {
default: { variant: "contained", color: "primary" },
destructive: { variant: "contained", color: "error" },
outline: { variant: "outlined", color: "primary", className: "border-border" },
ghost: { variant: "text", color: "inherit", className: "text-foreground" },
link: { variant: "text", color: "primary", className: "underline-offset-4 hover:underline" },
};
const sizeSx: Record<ButtonSize, ButtonProps["sx"]> = {
default: undefined,
lg: {
height: 42,
fontFamily: "var(--font-display)",
fontSize: "var(--text-base)",
fontWeight: 600,
},
};
export function Button({
variant = "default",
size = "default",
loading = false,
loadingText = "Loading…",
className,
disabled,
children,
sx,
...props
}: UiButtonProps) {
const mapped = variantMap[variant];
return (
<MuiButton
{...mapped}
disabled={disabled || loading}
aria-busy={loading || undefined}
aria-disabled={disabled || loading || undefined}
sx={[sizeSx[size], ...(Array.isArray(sx) ? sx : sx ? [sx] : [])]}
className={cn(mapped.className, className)}
{...props}
>
{loading ? (
<>
<CircularProgress size={16} color="inherit" sx={{ mr: 1 }} aria-hidden />
{loadingText}
</>
) : (
children
)}
</MuiButton>
);
}