diff --git a/src/components/ui/Badge.tsx b/src/components/ui/Badge.tsx index 60aaaf4..97fb6c8 100644 --- a/src/components/ui/Badge.tsx +++ b/src/components/ui/Badge.tsx @@ -1,18 +1,49 @@ "use client"; import React from 'react'; +import { Chip as HeroUIChip, ChipProps as HeroUIChipProps } from '@heroui/react'; +import { tv } from '@heroui/styles'; import { FiX } from 'react-icons/fi'; -export interface BadgeProps { - children: React.ReactNode; - variant?: - | 'default' - | 'primary' - | 'secondary' - | 'success' - | 'warning' - | 'danger' - | 'info' - | 'outline'; +// 1. Organizamos los estilos con 'tv' usando variantes estándar +const badgeStyles = tv({ + base: "inline-flex items-center select-none border transition-colors", + variants: { + customVariant: { + default: 'bg-slate-100 text-slate-800 border-slate-200 dark:bg-slate-800/80 dark:text-slate-200 dark:border-slate-700', + primary: 'bg-cyan-50 text-cyan-700 border-cyan-200 dark:bg-cyan-950/60 dark:text-cyan-300 dark:border-cyan-500/30', + secondary: 'bg-purple-50 text-purple-700 border-purple-200 dark:bg-purple-950/60 dark:text-purple-300 dark:border-purple-500/30', + success: 'bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-950/60 dark:text-emerald-300 dark:border-emerald-500/30', + warning: 'bg-amber-50 text-amber-700 border-amber-200 dark:bg-amber-950/60 dark:text-amber-300 dark:border-amber-500/30', + danger: 'bg-rose-50 text-rose-700 border-rose-200 dark:bg-rose-950/60 dark:text-rose-300 dark:border-rose-500/30', + info: 'bg-sky-50 text-sky-700 border-sky-200 dark:bg-sky-950/60 dark:text-sky-300 dark:border-sky-500/30', + outline: 'bg-transparent text-slate-700 border-slate-300 dark:text-slate-300 dark:border-slate-700', + }, + customSize: { + sm: 'text-[10px] px-2 py-0.5 gap-1 rounded-md font-semibold h-auto min-w-min', + md: 'text-xs px-2.5 py-1 gap-1.5 rounded-lg font-medium h-auto min-w-min', + lg: 'text-sm px-3 py-1.5 gap-2 rounded-xl font-medium h-auto min-w-min', + } + }, + defaultVariants: { + customVariant: "default", + customSize: "md", + } +}); + +// Mapeo auxiliar de colores para los dots según la variante +const dotColorMap: Record, string> = { + default: 'bg-slate-500', + primary: 'bg-cyan-500', + secondary: 'bg-purple-500', + success: 'bg-emerald-500', + warning: 'bg-amber-500', + danger: 'bg-rose-500', + info: 'bg-sky-500', + outline: 'bg-slate-400', +}; + +export interface BadgeProps extends Omit { + variant?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'outline'; size?: 'sm' | 'md' | 'lg'; dot?: boolean; dotPulse?: boolean; @@ -20,103 +51,71 @@ export interface BadgeProps { removable?: boolean; onRemove?: () => void; className?: string; + children?: React.ReactNode; } -const variantStyles: Record, { badge: string; dot: string }> = { - default: { - badge: 'bg-slate-100 text-slate-800 border-slate-200 dark:bg-slate-800/80 dark:text-slate-200 dark:border-slate-700', - dot: 'bg-slate-500', - }, - primary: { - badge: 'bg-cyan-50 text-cyan-700 border-cyan-200 dark:bg-cyan-950/60 dark:text-cyan-300 dark:border-cyan-500/30', - dot: 'bg-cyan-500', - }, - secondary: { - badge: 'bg-purple-50 text-purple-700 border-purple-200 dark:bg-purple-950/60 dark:text-purple-300 dark:border-purple-500/30', - dot: 'bg-purple-500', - }, - success: { - badge: 'bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-950/60 dark:text-emerald-300 dark:border-emerald-500/30', - dot: 'bg-emerald-500', - }, - warning: { - badge: 'bg-amber-50 text-amber-700 border-amber-200 dark:bg-amber-950/60 dark:text-amber-300 dark:border-amber-500/30', - dot: 'bg-amber-500', - }, - danger: { - badge: 'bg-rose-50 text-rose-700 border-rose-200 dark:bg-rose-950/60 dark:text-rose-300 dark:border-rose-500/30', - dot: 'bg-rose-500', - }, - info: { - badge: 'bg-sky-50 text-sky-700 border-sky-200 dark:bg-sky-950/60 dark:text-sky-300 dark:border-sky-500/30', - dot: 'bg-sky-500', - }, - outline: { - badge: 'bg-transparent text-slate-700 border-slate-300 dark:text-slate-300 dark:border-slate-700', - dot: 'bg-slate-400', - }, -}; +export const Badge = React.forwardRef( + ( + { + children, + variant = 'default', + size = 'md', + dot = false, + dotPulse = false, + icon, + removable = false, + onRemove, + className = '', + ...props + }, + ref + ) => { + const dotColor = dotColorMap[variant]; -const sizeStyles = { - sm: 'text-[10px] px-2 py-0.5 gap-1 rounded-md font-semibold', - md: 'text-xs px-2.5 py-1 gap-1.5 rounded-lg font-medium', - lg: 'text-sm px-3 py-1.5 gap-2 rounded-xl font-medium', -}; + return ( + + {/* Optional Dot indicator */} + {dot && ( + + {dotPulse && ( + + )} + + + )} -export const Badge: React.FC = ({ - children, - variant = 'default', - size = 'md', - dot = false, - dotPulse = false, - icon, - removable = false, - onRemove, - className = '', -}) => { - const currentVariant = variantStyles[variant]; + {/* Optional Icon */} + {icon && {icon}} - return ( - - {/* Optional Dot indicator */} - {dot && ( - - {dotPulse && ( - - )} - - - )} + {/* Content */} + {children} - {/* Optional Icon */} - {icon && {icon}} + {/* Optional Remove Button */} + {removable && ( + + )} + + ); + } +); - {/* Content */} - {children} - - {/* Optional Remove Button */} - {removable && ( - - )} - - ); -}; +Badge.displayName = 'Badge'; \ No newline at end of file