Token foundation: fix 16 palette colours to match official ADS_COLORS, add 5 new palettes (teal, brown, purple, fuchsia, yellow), realign semantic tokens (primary=navy, info=bright blue), fix border radii to 8px base, add responsive heading typography. Component migration: swap primary/info references across all existing components, update Button (44px/semibold), Switch (green/compact), Chip (30px/8px radius + colour variants), SideNav (80px rail), Tag (11 colours). New components: SideNav, TopBar, Avatar, Tabs, PageHeader, Slider, RangeSlider, FileInput, DataTable, List, Autocomplete. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
103 lines
2.7 KiB
TypeScript
103 lines
2.7 KiB
TypeScript
import { forwardRef, type HTMLAttributes } from 'react'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
// --- Card ---
|
|
|
|
export interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
variant?: 'surface' | 'outlined' | 'elevated' | 'filled'
|
|
}
|
|
|
|
const variantStyles: Record<string, string> = {
|
|
surface: 'bg-surface border border-border shadow-default',
|
|
outlined: 'bg-surface border border-border',
|
|
elevated: 'bg-surface shadow-md',
|
|
filled: 'bg-primary text-white',
|
|
}
|
|
|
|
export const Card = forwardRef<HTMLDivElement, CardProps>(
|
|
({ variant = 'surface', className, ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn('rounded-xl', variantStyles[variant], className)}
|
|
{...props}
|
|
/>
|
|
),
|
|
)
|
|
Card.displayName = 'Card'
|
|
|
|
// --- CardHeader ---
|
|
|
|
export interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {
|
|
action?: React.ReactNode
|
|
}
|
|
|
|
export const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(
|
|
({ action, className, children, ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn('flex items-start gap-3 px-6 pt-6', action && 'justify-between', className)}
|
|
{...props}
|
|
>
|
|
<div className="flex min-w-0 flex-1 flex-col gap-1">{children}</div>
|
|
{action && <div className="shrink-0">{action}</div>}
|
|
</div>
|
|
),
|
|
)
|
|
CardHeader.displayName = 'CardHeader'
|
|
|
|
// --- CardTitle ---
|
|
|
|
export type CardTitleProps = HTMLAttributes<HTMLHeadingElement>
|
|
|
|
export const CardTitle = forwardRef<HTMLHeadingElement, CardTitleProps>(
|
|
({ className, ...props }, ref) => (
|
|
<h3
|
|
ref={ref}
|
|
className={cn('text-h5 font-bold leading-tight', className)}
|
|
{...props}
|
|
/>
|
|
),
|
|
)
|
|
CardTitle.displayName = 'CardTitle'
|
|
|
|
// --- CardDescription ---
|
|
|
|
export type CardDescriptionProps = HTMLAttributes<HTMLParagraphElement>
|
|
|
|
export const CardDescription = forwardRef<HTMLParagraphElement, CardDescriptionProps>(
|
|
({ className, ...props }, ref) => (
|
|
<p
|
|
ref={ref}
|
|
className={cn('text-small text-text-secondary', className)}
|
|
{...props}
|
|
/>
|
|
),
|
|
)
|
|
CardDescription.displayName = 'CardDescription'
|
|
|
|
// --- CardContent ---
|
|
|
|
export type CardContentProps = HTMLAttributes<HTMLDivElement>
|
|
|
|
export const CardContent = forwardRef<HTMLDivElement, CardContentProps>(
|
|
({ className, ...props }, ref) => (
|
|
<div ref={ref} className={cn('px-6 py-4', className)} {...props} />
|
|
),
|
|
)
|
|
CardContent.displayName = 'CardContent'
|
|
|
|
// --- CardFooter ---
|
|
|
|
export type CardFooterProps = HTMLAttributes<HTMLDivElement>
|
|
|
|
export const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(
|
|
({ className, ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn('flex items-center gap-3 px-6 pb-6', className)}
|
|
{...props}
|
|
/>
|
|
),
|
|
)
|
|
CardFooter.displayName = 'CardFooter'
|