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>
97 lines
2.4 KiB
TypeScript
97 lines
2.4 KiB
TypeScript
import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
// --- List ---
|
|
|
|
export interface ListProps extends HTMLAttributes<HTMLUListElement> {}
|
|
|
|
export const List = forwardRef<HTMLUListElement, ListProps>(
|
|
({ className, children, ...props }, ref) => (
|
|
<ul
|
|
ref={ref}
|
|
role="list"
|
|
className={cn('flex flex-col bg-surface', className)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</ul>
|
|
),
|
|
)
|
|
List.displayName = 'List'
|
|
|
|
// --- ListItem ---
|
|
|
|
export interface ListItemProps extends HTMLAttributes<HTMLLIElement> {
|
|
icon?: ReactNode
|
|
active?: boolean
|
|
disabled?: boolean
|
|
href?: string
|
|
}
|
|
|
|
export const ListItem = forwardRef<HTMLLIElement, ListItemProps>(
|
|
({ icon, active = false, disabled = false, href, className, children, ...props }, ref) => {
|
|
const styles = cn(
|
|
'flex min-h-12 items-center gap-4 px-4 py-2 transition-colors',
|
|
active
|
|
? 'bg-info/12 text-info'
|
|
: 'text-text hover:bg-text/[0.04]',
|
|
disabled && 'pointer-events-none opacity-55',
|
|
className,
|
|
)
|
|
|
|
const content = (
|
|
<>
|
|
{icon && (
|
|
<span className={cn('size-6 shrink-0 [&>svg]:size-full', active ? 'text-info' : 'text-text-secondary')}>
|
|
{icon}
|
|
</span>
|
|
)}
|
|
<span className="flex-1 text-body">{children}</span>
|
|
</>
|
|
)
|
|
|
|
if (href) {
|
|
return (
|
|
<li ref={ref} {...props}>
|
|
<a href={href} className={styles}>{content}</a>
|
|
</li>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<li ref={ref} role="listitem" className={styles} {...props}>
|
|
{content}
|
|
</li>
|
|
)
|
|
},
|
|
)
|
|
ListItem.displayName = 'ListItem'
|
|
|
|
// --- ListSubheader ---
|
|
|
|
export interface ListSubheaderProps extends HTMLAttributes<HTMLLIElement> {}
|
|
|
|
export const ListSubheader = forwardRef<HTMLLIElement, ListSubheaderProps>(
|
|
({ className, children, ...props }, ref) => (
|
|
<li
|
|
ref={ref}
|
|
className={cn('flex min-h-10 items-center px-4 text-small font-semibold text-text-secondary', className)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</li>
|
|
),
|
|
)
|
|
ListSubheader.displayName = 'ListSubheader'
|
|
|
|
// --- ListDivider ---
|
|
|
|
export interface ListDividerProps extends HTMLAttributes<HTMLLIElement> {}
|
|
|
|
export const ListDivider = forwardRef<HTMLLIElement, ListDividerProps>(
|
|
({ className, ...props }, ref) => (
|
|
<li ref={ref} role="separator" className={cn('border-t border-border', className)} {...props} />
|
|
),
|
|
)
|
|
ListDivider.displayName = 'ListDivider'
|