O código define um componente de botão reutilizável em React, usando a biblioteca Radix UI e o class-variance-authority (cva)
para aplicar variações de estilos de forma dinâmica. A seguir, vamos analisar as partes do código em detalhes.
Importações
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils"
- React: A biblioteca principal usada para criar componentes no React.
- Slot: O
Slot
vem do Radix UI e é utilizado para permitir que o componenteButton
seja renderizado como um componente filho personalizado, se necessário. - cva: A função
cva
é usada para criar uma função de estilo dinâmica baseada nas variantes do botão, facilitando a gestão de classes CSS. - cn: Uma função personalizada que provavelmente une e limpa as classes passadas, facilitando a aplicação das classes no botão.
Definição das Variantes do Botão
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
Neste trecho, cva
é utilizado para definir o conjunto de estilos variáveis para o botão. Ele possui duas variantes principais:
- variant: Estilos como
default
,destructive
,outline
,secondary
,ghost
elink
, que modificam a aparência do botão (por exemplo, cor de fundo, cor do texto, bordas, etc.). - size: Define os tamanhos do botão, como
default
,sm
(pequeno),lg
(grande) eicon
(para ícones).
Componente Button
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
(<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props} />)
);
})
Button.displayName = "Button"
Button
é o componente principal que é encapsulado pela funçãoforwardRef
para permitir o uso de referências (ref
).- Propriedades:
- className: Permite adicionar classes CSS adicionais.
- variant: Define o estilo do botão (ex:
default
,destructive
). - size: Define o tamanho do botão (ex:
sm
,lg
). - asChild: Se
true
, o botão será renderizado como oSlot
, permitindo que ele seja um componente filho de outro componente. Caso contrário, o botão será renderizado normalmente como um<button>
.
Exportação
export { Button, buttonVariants }
O componente Button e as variantes de botão são exportados para serem usados em outros arquivos.
Código Completo
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
(<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props} />)
);
})
Button.displayName = "Button"
export { Button, buttonVariants }