162 lines
4.0 KiB
TypeScript
162 lines
4.0 KiB
TypeScript
import React, { forwardRef, ReactNode, HTMLAttributes } from 'react';
|
|
import { cn } from '../../lib/utils';
|
|
|
|
// Badge variants
|
|
type BadgeVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | 'neutral';
|
|
|
|
// Badge sizes
|
|
type BadgeSize = 'sm' | 'md' | 'lg';
|
|
|
|
// Badge props interface
|
|
interface BadgeProps extends HTMLAttributes<HTMLDivElement> {
|
|
variant?: BadgeVariant;
|
|
size?: BadgeSize;
|
|
icon?: ReactNode;
|
|
iconPosition?: 'left' | 'right';
|
|
rounded?: boolean;
|
|
children?: ReactNode;
|
|
}
|
|
|
|
// Helper function to get variant styles
|
|
const getVariantStyles = (variant: BadgeVariant) => {
|
|
switch (variant) {
|
|
case 'primary':
|
|
return 'bg-primary text-white';
|
|
case 'secondary':
|
|
return 'bg-secondary text-white';
|
|
case 'success':
|
|
return 'bg-success text-white';
|
|
case 'warning':
|
|
return 'bg-warning text-gray-900';
|
|
case 'error':
|
|
return 'bg-danger text-white';
|
|
case 'info':
|
|
return 'bg-info text-white';
|
|
case 'neutral':
|
|
return 'bg-gray-200 text-gray-800';
|
|
default:
|
|
return 'bg-primary text-white';
|
|
}
|
|
};
|
|
|
|
// Helper function to get size styles
|
|
const getSizeStyles = (size: BadgeSize) => {
|
|
switch (size) {
|
|
case 'sm':
|
|
return 'text-xs px-2 py-0.5';
|
|
case 'md':
|
|
return 'text-sm px-3 py-1';
|
|
case 'lg':
|
|
return 'text-base px-4 py-1.5';
|
|
default:
|
|
return 'text-sm px-3 py-1';
|
|
}
|
|
};
|
|
|
|
// Helper function to get icon spacing
|
|
const getIconSpacing = (size: BadgeSize, iconPosition: 'left' | 'right') => {
|
|
const spacing = {
|
|
sm: iconPosition === 'left' ? 'mr-1' : 'ml-1',
|
|
md: iconPosition === 'left' ? 'mr-1.5' : 'ml-1.5',
|
|
lg: iconPosition === 'left' ? 'mr-2' : 'ml-2',
|
|
};
|
|
return spacing[size];
|
|
};
|
|
|
|
// Helper function to get icon size
|
|
const getIconSize = (size: BadgeSize) => {
|
|
const sizeClasses = {
|
|
sm: 'w-3 h-3',
|
|
md: 'w-4 h-4',
|
|
lg: 'w-5 h-5',
|
|
};
|
|
return sizeClasses[size];
|
|
};
|
|
|
|
// Main Badge Component
|
|
export const Badge = forwardRef<HTMLDivElement, BadgeProps>(
|
|
(
|
|
{
|
|
variant = 'primary',
|
|
size = 'md',
|
|
icon,
|
|
iconPosition = 'left',
|
|
rounded = true,
|
|
className = '',
|
|
children,
|
|
...props
|
|
},
|
|
ref
|
|
) => {
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
// Base styles
|
|
'inline-flex items-center justify-center font-medium',
|
|
'transition-all duration-200 ease-in-out',
|
|
// Variant styles
|
|
getVariantStyles(variant),
|
|
// Size styles
|
|
getSizeStyles(size),
|
|
// Border radius
|
|
rounded ? 'rounded-full' : 'rounded-md',
|
|
// Custom classes
|
|
className
|
|
)}
|
|
{...props}
|
|
>
|
|
{/* Icon - Left position */}
|
|
{icon && iconPosition === 'left' && (
|
|
<span className={cn('flex items-center justify-center', getIconSpacing(size, 'left'), getIconSize(size))}>
|
|
{icon}
|
|
</span>
|
|
)}
|
|
|
|
{/* Badge content */}
|
|
{children && <span>{children}</span>}
|
|
|
|
{/* Icon - Right position */}
|
|
{icon && iconPosition === 'right' && (
|
|
<span className={cn('flex items-center justify-center', getIconSpacing(size, 'right'), getIconSize(size))}>
|
|
{icon}
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
|
|
Badge.displayName = 'Badge';
|
|
|
|
// Badge Group Component for multiple badges
|
|
interface BadgeGroupProps extends HTMLAttributes<HTMLDivElement> {
|
|
children?: ReactNode;
|
|
gap?: 'xs' | 'sm' | 'md' | 'lg';
|
|
}
|
|
|
|
export const BadgeGroup = forwardRef<HTMLDivElement, BadgeGroupProps>(
|
|
({ gap = 'sm', className = '', children, ...props }, ref) => {
|
|
const gapClasses = {
|
|
xs: 'gap-1',
|
|
sm: 'gap-2',
|
|
md: 'gap-3',
|
|
lg: 'gap-4',
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn('flex flex-wrap items-center', gapClasses[gap], className)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
|
|
BadgeGroup.displayName = 'BadgeGroup';
|
|
|
|
// Export types for external use
|
|
export type { BadgeProps, BadgeVariant, BadgeSize, BadgeGroupProps }; |