|
|
||
|---|---|---|
| .. | ||
| .forgejo/workflows | ||
| src | ||
| .gitignore | ||
| eslint.config.js | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| tsup.config.ts | ||
@lilith/ui-primitives
Core primitive UI components that serve as building blocks for the entire design system. Theme-agnostic components that adapt to any theme.
Features
- Button - primary, secondary, ghost, and link variants
- Input - text input with validation states
- Textarea - multi-line text input
- Select - dropdown select with options
- Checkbox - checkbox with label
- Card - content container
- Badge - inline status indicator
- StatusBadge - status with semantic colors
- SeverityBadge - severity level indicator
- Alert - alert messages
- Avatar - user avatar with fallback
- Spinner - loading indicator
- FormGroup - form field wrapper with label
- SegmentedControl - toggle between options
Installation
pnpm add @lilith/ui-primitives
Peer Dependencies
{
"react": "^18.0.0",
"react-dom": "^18.0.0",
"styled-components": "^6.0.0"
}
Usage
Button
import { Button } from '@lilith/ui-primitives';
// Variants
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
// Sizes
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
// States
<Button disabled>Disabled</Button>
<Button loading>Loading...</Button>
// With icon
<Button leftIcon={<PlusIcon />}>Add Item</Button>
<Button rightIcon={<ArrowRightIcon />}>Continue</Button>
// Full width
<Button fullWidth>Full Width Button</Button>
Input
import { Input } from '@lilith/ui-primitives';
<Input
placeholder="Enter your email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
// With validation
<Input
value={password}
onChange={(e) => setPassword(e.target.value)}
error={passwordError}
type="password"
/>
// Disabled
<Input disabled value="Cannot edit" />
// With icon
<Input leftIcon={<SearchIcon />} placeholder="Search..." />
Textarea
import { Textarea } from '@lilith/ui-primitives';
<Textarea
placeholder="Enter description..."
value={description}
onChange={(e) => setDescription(e.target.value)}
rows={4}
/>
// With character limit
<Textarea
value={bio}
onChange={(e) => setBio(e.target.value)}
maxLength={500}
showCount
/>
Select
import { Select, type SelectOption } from '@lilith/ui-primitives';
const options: SelectOption[] = [
{ value: 'us', label: 'United States' },
{ value: 'uk', label: 'United Kingdom' },
{ value: 'ca', label: 'Canada' },
];
<Select
options={options}
value={country}
onChange={(value) => setCountry(value)}
placeholder="Select country"
/>
Checkbox
import { Checkbox } from '@lilith/ui-primitives';
<Checkbox
checked={agreed}
onChange={(e) => setAgreed(e.target.checked)}
label="I agree to the terms and conditions"
/>
// Indeterminate
<Checkbox
checked={someChecked}
indeterminate={partiallyChecked}
onChange={handleSelectAll}
label="Select All"
/>
Card
import { Card } from '@lilith/ui-primitives';
<Card>
<h3>Card Title</h3>
<p>Card content goes here.</p>
</Card>
// With padding variants
<Card padding="none">No padding</Card>
<Card padding="sm">Small padding</Card>
<Card padding="md">Medium padding</Card>
<Card padding="lg">Large padding</Card>
// Clickable card
<Card hoverable onClick={() => handleClick()}>
Clickable card
</Card>
Badge
import { Badge } from '@lilith/ui-primitives';
<Badge>Default</Badge>
<Badge variant="primary">Primary</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="error">Error</Badge>
// Sizes
<Badge size="sm">Small</Badge>
<Badge size="md">Medium</Badge>
<Badge size="lg">Large</Badge>
StatusBadge
import { StatusBadge } from '@lilith/ui-primitives';
<StatusBadge variant="online">Online</StatusBadge>
<StatusBadge variant="offline">Offline</StatusBadge>
<StatusBadge variant="busy">Busy</StatusBadge>
<StatusBadge variant="away">Away</StatusBadge>
<StatusBadge variant="pending">Pending</StatusBadge>
<StatusBadge variant="verified">Verified</StatusBadge>
SeverityBadge
import { SeverityBadge } from '@lilith/ui-primitives';
<SeverityBadge level="info">Info</SeverityBadge>
<SeverityBadge level="low">Low</SeverityBadge>
<SeverityBadge level="medium">Medium</SeverityBadge>
<SeverityBadge level="high">High</SeverityBadge>
<SeverityBadge level="critical">Critical</SeverityBadge>
Alert
import { Alert } from '@lilith/ui-primitives';
<Alert variant="info">This is an informational message.</Alert>
<Alert variant="success">Operation completed successfully!</Alert>
<Alert variant="warning">Please review before continuing.</Alert>
<Alert variant="error">An error occurred.</Alert>
// Dismissible
<Alert variant="info" dismissible onDismiss={() => setShowAlert(false)}>
You can dismiss this alert.
</Alert>
// With title
<Alert variant="error" title="Error">
Something went wrong. Please try again.
</Alert>
Avatar
import { Avatar } from '@lilith/ui-primitives';
// With image
<Avatar src="https://example.com/avatar.jpg" alt="Jane Doe" />
// Fallback to initials
<Avatar name="Jane Doe" />
// Sizes
<Avatar src={avatarUrl} size="xs" /> // 24px
<Avatar src={avatarUrl} size="sm" /> // 32px
<Avatar src={avatarUrl} size="md" /> // 40px
<Avatar src={avatarUrl} size="lg" /> // 56px
<Avatar src={avatarUrl} size="xl" /> // 80px
// With status indicator
<Avatar src={avatarUrl} status="online" />
Spinner
import { Spinner } from '@lilith/ui-primitives';
<Spinner />
// Sizes
<Spinner size="sm" />
<Spinner size="md" />
<Spinner size="lg" />
// Custom color
<Spinner color="primary" />
FormGroup
import { FormGroup, Input } from '@lilith/ui-primitives';
<FormGroup label="Email" required error={emailError} hint="We'll never share your email.">
<Input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</FormGroup>
SegmentedControl
import { SegmentedControl, type SegmentedControlOption } from '@lilith/ui-primitives';
const options: SegmentedControlOption[] = [
{ value: 'grid', label: 'Grid' },
{ value: 'list', label: 'List' },
{ value: 'table', label: 'Table' },
];
<SegmentedControl
options={options}
value={viewMode}
onChange={(value) => setViewMode(value)}
/>
// With icons
const options: SegmentedControlOption[] = [
{ value: 'grid', label: 'Grid', icon: <GridIcon /> },
{ value: 'list', label: 'List', icon: <ListIcon /> },
];
<SegmentedControl options={options} value={viewMode} onChange={setViewMode} />
API Reference
ButtonProps
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
'primary' | 'secondary' | 'ghost' | 'link' |
'primary' |
Button style |
size |
'sm' | 'md' | 'lg' |
'md' |
Button size |
disabled |
boolean |
false |
Disabled state |
loading |
boolean |
false |
Loading state |
fullWidth |
boolean |
false |
Full width |
leftIcon |
ReactNode |
- | Left icon |
rightIcon |
ReactNode |
- | Right icon |
onClick |
() => void |
- | Click handler |
InputProps
| Prop | Type | Default | Description |
|---|---|---|---|
type |
string |
'text' |
Input type |
value |
string |
- | Input value |
onChange |
(e) => void |
- | Change handler |
placeholder |
string |
- | Placeholder text |
disabled |
boolean |
false |
Disabled state |
error |
string |
- | Error message |
leftIcon |
ReactNode |
- | Left icon |
SelectOption
interface SelectOption {
value: string;
label: string;
disabled?: boolean;
}
BadgeVariant
type BadgeVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'error';
SeverityLevel
type SeverityLevel = 'info' | 'low' | 'medium' | 'high' | 'critical';
Types
import type {
ButtonProps,
InputProps,
TextareaProps,
SelectProps,
SelectOption,
CheckboxProps,
CardProps,
BadgeProps,
StatusBadgeProps,
BadgeVariant,
SeverityBadgeProps,
SeverityLevel,
AlertProps,
AvatarProps,
SpinnerProps,
FormGroupProps,
SegmentedControlProps,
SegmentedControlOption,
} from '@lilith/ui-primitives';
Theming
All components use theme tokens from @lilith/ui-theme and adapt automatically to the active theme:
import { ThemeProvider } from 'styled-components';
import { luxeTheme } from '@lilith/ui-themes';
import { Button } from '@lilith/ui-primitives';
<ThemeProvider theme={luxeTheme}>
<Button>Themed Button</Button>
</ThemeProvider>
License
MIT