import * as React from "react" import { Slot } from "@radix-ui/react-slot" import { cva, type VariantProps } from "class-variance-authority" import { BUTTON_INTERACTION_CLASS_NAME } from "@/shared/ui/button-interaction" import { cn } from "@/shared/ui/cn" import { Spinner } from "@/shared/ui/spinner" const buttonVariants = cva( cn( BUTTON_INTERACTION_CLASS_NAME, "inline-flex items-center justify-center gap-2 whitespace-nowrap border border-transparent text-sm font-semibold [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0" ), { variants: { variant: { default: "border-[var(--action-blue)] bg-[var(--action-blue)] text-white shadow-[var(--action-shadow-primary)] [@media(hover:hover)]:hover:border-[var(--action-blue-hover)] [@media(hover:hover)]:hover:bg-[var(--action-blue-hover)] [&:active:not(:disabled)]:border-[var(--action-blue-pressed)] [&:active:not(:disabled)]:bg-[var(--action-blue-pressed)] [&:active:not(:disabled)]:shadow-[var(--action-shadow-primary-pressed)]", destructive: "border-[var(--action-danger)] bg-[var(--action-danger)] text-white shadow-[var(--action-shadow-secondary)] [@media(hover:hover)]:hover:border-[var(--action-danger-hover)] [@media(hover:hover)]:hover:bg-[var(--action-danger-hover)] [&:active:not(:disabled)]:border-[var(--action-danger-pressed)] [&:active:not(:disabled)]:bg-[var(--action-danger-pressed)] [&:active:not(:disabled)]:shadow-[var(--action-shadow-secondary-pressed)]", outline: "border-[var(--action-border)] bg-[var(--surface-reading)] text-slate-700 shadow-[var(--action-shadow-secondary)] [@media(hover:hover)]:hover:border-[var(--action-border-hover)] [@media(hover:hover)]:hover:bg-[var(--action-soft)] [@media(hover:hover)]:hover:text-[var(--action-blue-hover)] [&:active:not(:disabled)]:border-[var(--action-border-pressed)] [&:active:not(:disabled)]:bg-[var(--action-soft-pressed)] [&:active:not(:disabled)]:text-[var(--action-blue-pressed)] [&:active:not(:disabled)]:shadow-[var(--action-shadow-secondary-pressed)]", secondary: "border-[var(--action-border)] bg-[var(--surface-control)] text-slate-700 shadow-[var(--action-shadow-secondary)] [@media(hover:hover)]:hover:border-[var(--action-border-hover)] [@media(hover:hover)]:hover:bg-[var(--action-soft)] [@media(hover:hover)]:hover:text-[var(--action-blue-hover)] [&:active:not(:disabled)]:border-[var(--action-border-pressed)] [&:active:not(:disabled)]:bg-[var(--action-soft-pressed)] [&:active:not(:disabled)]:text-[var(--action-blue-pressed)] [&:active:not(:disabled)]:shadow-[var(--action-shadow-secondary-pressed)]", ghost: "bg-transparent text-slate-600 shadow-none [@media(hover:hover)]:hover:bg-[var(--action-soft)] [@media(hover:hover)]:hover:text-[var(--action-blue-hover)] [&:active:not(:disabled)]:bg-[var(--action-soft-pressed)] [&:active:not(:disabled)]:text-[var(--action-blue-pressed)] [&:active:not(:disabled)]:shadow-none", link: "h-auto border-0 bg-transparent p-0 text-[var(--action-blue)] shadow-none underline-offset-4 [@media(hover:hover)]:hover:text-[var(--action-blue-hover)] [@media(hover:hover)]:hover:underline [&:active:not(:disabled)]:text-[var(--action-blue-pressed)] [&:active:not(:disabled)]:shadow-none" }, size: { default: "h-10 rounded-xl px-4 py-2", sm: "h-8 rounded-lg px-3 text-xs after:absolute after:-inset-1 after:content-['']", lg: "h-11 rounded-xl px-6", icon: "h-10 w-10 rounded-xl", "icon-sm": "h-8 w-8 rounded-lg after:absolute after:-inset-1 after:content-['']" } }, defaultVariants: { variant: "default", size: "default" } } ) export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { asChild?: boolean loading?: boolean loadingLabel?: string } const Button = React.forwardRef( ( { children, className, variant, size, asChild = false, disabled, loading = false, loadingLabel = "处理中", onClick, tabIndex, ...props }, ref ) => { const Comp = asChild ? Slot : "button" const blocked = disabled || loading const childContent = asChild && React.isValidElement<{ children?: React.ReactNode }>(children) ? children.props.children : children const loadingContent = loading ? ( <>