import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
// Loading 图标组件
export const LoadingIcon = ({ className }: { className?: string }) => (
)
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap transition-all disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive cursor-pointer",
{
variants: {
variant: {
primary:
"bg-primary-gradient-normal disabled:bg-none disabled:bg-primary-variant-disabled disabled:text-txt-primary-disabled disabled:backdrop-blur-lg text-txt-primary-specialmap-normal shadow-xs hover:bg-primary-gradient-hover active:bg-primary-gradient-press",
secondary: "border border-solid border-primary-variant-normal text-primary-variant-normal disabled:border-primary-variant-disabled disabled:text-txt-primary-disabled hover:border-primary-variant-hover hover:text-primary-variant-hover active:border-primary-variant-press active:text-primary-variant-press",
tertiary: "bg-surface-element-normal text-txt-primary-normal disabled:bg-surface-element-disabled disabled:text-txt-primary-disabled hover:bg-surface-element-hover active:bg-surface-element-press",
tertiaryDark: "bg-surface-element-dark-normal text-txt-primary-normal disabled:bg-surface-element-dark-disabled disabled:text-txt-primary-disabled hover:bg-surface-element-dark-hover active:bg-surface-element-dark-press",
destructive: "bg-important-normal text-txt-primary-normal disabled:bg-important-disabled disabled:text-txt-primary-disabled disabled:backdrop-blur-lg hover:bg-important-hover active:bg-important-press",
ghost: "bg-transparent text-primary-variant-normal disabled:text-txt-primary-disabled hover:bg-surface-element-hover hover:backdrop-blur-[16px] active:bg-surface-element-press",
vip: "bg-gradient-secondary-normal text-black"
},
size: {
large: "min-w-[128px] h-12 rounded-full px-8 has-[>svg]:px-6 txt-label-l",
small: "min-w-[80px] h-8 rounded-full px-4 has-[>svg]:px-2 txt-label-s",
icon: "size-9",
},
block: {
true: "w-full",
false: "",
},
loading: {
true: "cursor-not-allowed backdrop-blur backdrop-filter",
false: "",
},
},
defaultVariants: {
variant: "primary",
size: "large",
block: false,
loading: false,
},
}
)
const iconButtonVariants = cva(
"inline-flex items-center justify-center transition-all disabled:pointer-events-none [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none rounded-full cursor-pointer",
{
variants: {
variant: {
default: "bg-primary-gradient-normal text-txt-primary-normal disabled:bg-primary-gradient-disabled disabled:bg-none disabled:text-txt-primary-disabled hover:bg-primary-gradient-hover active:bg-primary-gradient-press",
primary: "bg-primary-normal text-txt-primary-normal disabled:bg-primary-disabled disabled:text-txt-primary-disabled hover:bg-primary-hover active:bg-primary-press",
tertiary: "bg-surface-element-normal text-txt-primary-normal disabled:bg-surface-element-disabled disabled:text-txt-primary-disabled hover:bg-surface-element-hover active:bg-surface-element-press",
tertiaryDark: "bg-surface-element-dark-normal text-txt-primary-normal disabled:bg-surface-element-dark-disabled disabled:text-txt-primary-specialmap-disable hover:bg-surface-element-dark-hover active:bg-surface-element-dark-press",
contrast: "bg-surface-element-light-normal text-txt-primary-normal disabled:bg-surface-element-light-disabled disabled:text-txt-primary-disabled hover:bg-surface-element-light-hover active:bg-surface-element-light-press",
ghost: "bg-transparent text-txt-primary-normal disabled:text-txt-primary-disabled hover:bg-surface-element-hover hover:backdrop-blur-[16px] active:bg-surface-element-press",
destructive: "bg-important-normal text-txt-primary-normal disabled:bg-important-disabled disabled:text-txt-primary-disabled disabled:backdrop-blur-lg hover:bg-important-hover active:bg-important-press",
},
size: {
large: "size-12 [&_svg:not([class*='size-'])]:size-6 [&_i]:!text-[24px]",
small: "size-8 [&_svg:not([class*='size-'])]:size-4 [&_i]:!text-[16px]",
xs: "size-6 [&_svg:not([class*='size-'])]:size-3 [&_i]:!text-[12px]",
mini: "size-4 [&_svg:not([class*='size-'])]:size-2 [&_i]:!text-[8px]",
},
loading: {
true: "cursor-not-allowed backdrop-blur backdrop-filter",
false: "",
},
},
defaultVariants: {
variant: "default",
size: "large",
loading: false,
},
}
)
function Button({
className,
variant,
size,
block,
loading = false,
children,
asChild = false,
disabled,
...props
}: React.ComponentProps<"button"> &
VariantProps & {
asChild?: boolean,
block?: boolean,
loading?: boolean
}) {
const Comp = asChild ? Slot : "button"
// 当 loading 为 true 时,自动禁用按钮
const isDisabled = disabled || loading
return (
{loading && (
)}
{/* 当 loading 时,如果有 children 则显示,否则只显示 loading 图标 */}
{!loading ? children : null}
)
}
function IconButton({
className,
variant,
iconfont,
size,
loading = false,
children,
asChild = false,
disabled,
...props
}: React.ComponentProps<"button"> &
VariantProps & {
iconfont?: string,
asChild?: boolean,
loading?: boolean
}) {
const Comp = asChild ? Slot : "button"
// 当 loading 为 true 时,自动禁用按钮
const isDisabled = disabled || loading
return (
{loading ? (
) : (
<>
{iconfont && }
{children}
>
)}
)
}
export { Button, IconButton, buttonVariants, iconButtonVariants }