feat(ui): add surface layout primitives

This commit is contained in:
Saravana Achu Mac 2026-05-06 11:21:50 -07:00
parent f37fd480fe
commit 48ad3deb7f
2 changed files with 108 additions and 0 deletions

View File

@ -0,0 +1,100 @@
import * as React from 'react';
import { clsx } from 'clsx';
export interface SurfaceProps extends React.HTMLAttributes<HTMLElement> {
as?: 'section' | 'aside' | 'article' | 'div';
variant?: 'default' | 'muted' | 'elevated' | 'outline' | 'plain';
padding?: 'none' | 'sm' | 'md' | 'lg';
}
const surfaceVariants: Record<NonNullable<SurfaceProps['variant']>, string> = {
default: 'border border-[var(--bl-border)] bg-[var(--bl-surface-card)]',
muted: 'border border-[var(--bl-border)] bg-[var(--bl-surface-muted)]',
elevated: 'border border-[var(--bl-border)] bg-[var(--bl-bg-elevated)] shadow-sm',
outline: 'border border-[var(--bl-border)] bg-transparent',
plain: 'border-transparent bg-transparent',
};
const surfacePadding: Record<NonNullable<SurfaceProps['padding']>, string> = {
none: '',
sm: 'p-3',
md: 'p-4',
lg: 'p-6',
};
export function Surface({
as: Comp = 'section',
variant = 'default',
padding = 'md',
className,
children,
...props
}: SurfaceProps) {
return (
<Comp
className={clsx(
'rounded-lg text-[var(--bl-text-primary)]',
surfaceVariants[variant],
surfacePadding[padding],
className
)}
{...props}
>
{children}
</Comp>
);
}
export interface SurfaceListProps extends React.HTMLAttributes<HTMLDivElement> {
density?: 'compact' | 'normal' | 'spacious';
divided?: boolean;
}
const listDensity: Record<NonNullable<SurfaceListProps['density']>, string> = {
compact: 'gap-1',
normal: 'gap-2',
spacious: 'gap-3',
};
export function SurfaceList({
density = 'normal',
divided,
className,
children,
...props
}: SurfaceListProps) {
return (
<div
className={clsx(
'grid',
listDensity[density],
divided &&
'divide-y divide-[var(--bl-border)] overflow-hidden rounded-lg border border-[var(--bl-border)]',
className
)}
{...props}
>
{children}
</div>
);
}
export interface SurfaceListItemProps extends React.HTMLAttributes<HTMLDivElement> {
selected?: boolean;
}
export function SurfaceListItem({ selected, className, children, ...props }: SurfaceListItemProps) {
return (
<div
data-selected={selected ? 'true' : undefined}
className={clsx(
'rounded-md border border-[var(--bl-border)] bg-[var(--bl-surface-muted)] p-3 text-[var(--bl-text-primary)]',
selected && 'border-[var(--bl-accent)] bg-[var(--bl-accent-muted,var(--bl-surface-card))]',
className
)}
{...props}
>
{children}
</div>
);
}

View File

@ -33,6 +33,14 @@ export {
type PanelProps,
type PanelTitleProps,
} from './components/Panel';
export {
Surface,
SurfaceList,
SurfaceListItem,
type SurfaceListItemProps,
type SurfaceListProps,
type SurfaceProps,
} from './components/Surface';
export { ListItemButton, type ListItemButtonProps } from './components/ListItemButton';
export { Timeline, type TimelineItem, type TimelineProps } from './components/Timeline';
export { DiffCard, type DiffCardProps } from './components/DiffCard';