import React, { ReactNode, forwardRef } from 'react'; import { Heading } from './Heading'; import { Spacing } from './Box'; export interface CardProps { children: ReactNode; variant?: 'default' | 'muted' | 'outline' | 'glass' | 'dark' | 'precision' | 'bordered' | 'elevated' | 'rarity-common' | 'rarity-rare' | 'rarity-epic' | 'rarity-legendary'; title?: string | ReactNode; footer?: ReactNode; padding?: 'none' | 'sm' | 'md' | 'lg' | number; onClick?: () => void; fullHeight?: boolean; 'data-testid'?: string; /** @deprecated Use semantic props instead. */ className?: string; /** @deprecated Use semantic props instead. */ style?: React.CSSProperties; /** @deprecated Use semantic props instead. */ p?: number; /** @deprecated Use semantic props instead. */ py?: number; /** @deprecated Use semantic props instead. */ mb?: number; /** @deprecated Use semantic props instead. */ bg?: string; /** @deprecated Use semantic props instead. */ borderColor?: string; /** @deprecated Use semantic props instead. */ hoverBorderColor?: string; /** @deprecated Use semantic props instead. */ border?: boolean; /** @deprecated Use semantic props instead. */ position?: string; /** @deprecated Use semantic props instead. */ overflow?: string; /** @deprecated Use semantic props instead. */ center?: boolean; /** @deprecated Use semantic props instead. */ rounded?: string | boolean; /** @deprecated Use semantic props instead. */ transition?: string | boolean; /** @deprecated Use semantic props instead. */ group?: boolean; /** @deprecated Use semantic props instead. */ responsiveColSpan?: { lg: number }; /** @deprecated Use semantic props instead. */ backgroundColor?: string; /** @deprecated Use semantic props instead. */ w?: string | number; /** @deprecated Use semantic props instead. */ display?: string; /** @deprecated Use semantic props instead. */ alignItems?: string; /** @deprecated Use semantic props instead. */ gap?: number; /** @deprecated Use semantic props instead. */ borderLeft?: boolean; /** @deprecated Use semantic props instead. */ justifyContent?: string; } /** * Card - Redesigned for "Modern Precision" theme. * Enforces semantic props. */ export const Card = forwardRef(({ children, variant = 'default', title, footer, padding = 'md', onClick, fullHeight, className, style: styleProp, p, py, mb, bg, borderColor, hoverBorderColor, border, position, overflow, center, rounded, transition, group, responsiveColSpan, backgroundColor, w, display, alignItems, gap, borderLeft, justifyContent, ...props }, ref) => { const variantClasses = { default: 'bg-[var(--ui-color-bg-surface)] border-[var(--ui-color-border-default)] shadow-sm', muted: 'bg-[var(--ui-color-bg-surface-muted)] border-[var(--ui-color-border-muted)]', outline: 'bg-transparent border-[var(--ui-color-border-default)]', glass: 'bg-white/[0.03] backdrop-blur-md border-white/[0.05]', dark: 'bg-[var(--ui-color-bg-base)] border-[var(--ui-color-border-default)]', precision: 'bg-[var(--ui-color-bg-surface)] border-[var(--ui-color-border-default)] shadow-[inset_0_1px_0_0_rgba(255,255,255,0.02)]', bordered: 'bg-[var(--ui-color-bg-surface)] border-[var(--ui-color-border-default)]', elevated: 'bg-[var(--ui-color-bg-surface)] border-[var(--ui-color-border-default)] shadow-md', 'rarity-common': 'bg-gray-500/10 border-gray-500/50', 'rarity-rare': 'bg-blue-500/10 border-blue-500/50', 'rarity-epic': 'bg-purple-500/10 border-purple-500/50', 'rarity-legendary': 'bg-orange-500/10 border-orange-500/50', }; const paddingClasses: Record = { none: 'p-0', sm: 'p-2', md: 'p-4', lg: 'p-8', }; const classes = [ 'border', variantClasses[variant as keyof typeof variantClasses] || variantClasses.default, typeof padding === 'string' ? (paddingClasses[padding] || paddingClasses.md) : '', onClick ? 'cursor-pointer hover:border-[var(--ui-color-border-bright)] transition-all duration-200' : '', fullHeight ? 'h-full flex flex-col' : '', group ? 'group' : '', rounded === true ? 'rounded-full' : (typeof rounded === 'string' ? `rounded-${rounded}` : 'rounded-none'), className, ].filter(Boolean).join(' '); const style: React.CSSProperties = { ...(typeof padding === 'number' ? { padding: `${padding * 0.25}rem` } : {}), ...(p !== undefined ? { padding: `${p * 0.25}rem` } : {}), ...(py !== undefined ? { paddingTop: `${py * 0.25}rem`, paddingBottom: `${py * 0.25}rem` } : {}), ...(mb !== undefined ? { marginBottom: `${mb * 0.25}rem` } : {}), ...(bg ? { backgroundColor: bg.startsWith('bg-') ? undefined : bg } : {}), ...(backgroundColor ? { backgroundColor } : {}), ...(borderColor ? { borderColor: borderColor.startsWith('border-') ? undefined : borderColor } : {}), ...(hoverBorderColor ? { '--hover-border-color': hoverBorderColor } as any : {}), ...(border === false ? { border: 'none' } : {}), ...(position ? { position: position as any } : {}), ...(overflow ? { overflow } : {}), ...(center ? { display: 'flex', alignItems: 'center', justifyContent: 'center' } : {}), ...(typeof transition === 'string' ? { transition } : {}), ...(responsiveColSpan?.lg ? { gridColumn: `span ${responsiveColSpan.lg} / span ${responsiveColSpan.lg}` } : {}), ...(w !== undefined ? { width: w } : {}), ...(display ? { display } : {}), ...(alignItems ? { alignItems } : {}), ...(justifyContent ? { justifyContent } : {}), ...(gap !== undefined ? { gap: `${gap * 0.25}rem` } : {}), ...(borderLeft ? { borderLeft: `4px solid var(--ui-color-intent-primary)` } : {}), ...(styleProp || {}), }; return (
0 ? style : undefined} data-testid={props['data-testid'] as string} {...props} > {title && (
{typeof title === 'string' ? ( {title} ) : title}
)}
{children}
{footer && (
{footer}
)}
); }); Card.displayName = 'Card'; export const CardHeader = ({ title, children }: { title?: string, children?: ReactNode }) => (
{title && {title}} {children}
); export const CardContent = ({ children }: { children: ReactNode }) => (
{children}
); export const CardFooter = ({ children }: { children: ReactNode }) => (
{children}
);