mirror of
https://github.com/hanzoai/o11y-components.git
synced 2026-10-30 14:54:15 +00:00
A version written into a manifest is written into every manifest that wants it, which is how eslint came to exist in a hundred and four forms across this estate and how a package came to resolve twice at run time. The catalog moves the number out of the manifest: a manifest names the package, the workspace names the version. Four are held below their latest because the newer release cannot be used, and the reason is recorded rather than the version alone: @noble/hashes 2 renamed every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels 3 points its types condition at the bundle.
289 lines
9.7 KiB
Plaintext
289 lines
9.7 KiB
Plaintext
import { Meta } from '@storybook/addon-docs/blocks';
|
|
|
|
<Meta title="Design System / Overview" />
|
|
|
|
# Overview
|
|
|
|
This section covers the design system foundations: token hierarchy, installation, usage patterns, surface levels, extending tokens for new components, and migration from legacy tokens. For the interactive token reference, see [Design System / Tokens](?path=/docs/design-system-tokens--docs).
|
|
|
|
## Token Hierarchy
|
|
|
|
Our token system follows a three-tier hierarchy:
|
|
|
|
```
|
|
Diagram of the token hierarchy:
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Components │
|
|
│ Dialog, Button, Card, etc. use semantic tokens │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
▲
|
|
│ uses
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Semantic Tokens │
|
|
│ l1-background, primary-background, accent-cherry, etc. │
|
|
│ Purpose-driven: "what it's for" │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
▲
|
|
│ references
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Primitive Tokens │
|
|
│ robin-500, cherry-400, neutral-dark-900, etc. │
|
|
│ Raw values: "what color it is" │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Why this matters:**
|
|
- **Primitives** are raw color values (e.g., `robin-500: #4E74F8`)
|
|
- **Semantic tokens** give meaning to those values (e.g., `primary-background: var(--bg-robin-500)`)
|
|
- **Components** use semantic tokens, making theme changes automatic
|
|
|
|
---
|
|
|
|
|
|
## Token Usage
|
|
|
|
### CSS Variables
|
|
|
|
All tokens are available as CSS custom properties:
|
|
|
|
```css
|
|
.my-element {
|
|
background-color: var(--l1-background);
|
|
color: var(--l1-foreground);
|
|
border: 1px solid var(--l2-border);
|
|
}
|
|
```
|
|
|
|
### Tailwind Classes
|
|
|
|
Tokens are mapped to Tailwind utility classes:
|
|
|
|
```tsx
|
|
<div style={{ backgroundColor: 'var(--l1-background)', color: 'var(--l1-foreground)', borderStyle: 'solid', borderWidth: 1, borderColor: 'var(--l2-border)' }}>
|
|
Content here
|
|
</div>
|
|
```
|
|
|
|
### When to Use Which
|
|
|
|
| Approach | Best For |
|
|
|----------|----------|
|
|
| **Tailwind classes** | Component styling, responsive design, rapid prototyping |
|
|
| **CSS variables** | Complex animations, dynamic theming, CSS-in-JS libraries |
|
|
|
|
---
|
|
|
|
## Surface Level System
|
|
|
|
The surface level system provides a consistent approach to layered UI. Each level (L1, L2, L3) represents a different depth in the visual hierarchy.
|
|
|
|
### L1 - Page Background
|
|
|
|
The outermost container, typically the page or app shell background.
|
|
|
|
```tsx
|
|
<div style={{ backgroundColor: 'var(--l1-background)', color: 'var(--l1-foreground)' }}>
|
|
{/* Page content */}
|
|
</div>
|
|
```
|
|
|
|
**Use for:** Main app shell, page backgrounds, root containers
|
|
|
|
**Don't use for:** Cards, modals, or nested elements
|
|
|
|
### L2 - Cards and Panels
|
|
|
|
Secondary surfaces that sit on top of L1.
|
|
|
|
```tsx
|
|
<div style={{ backgroundColor: 'var(--l1-background)' }}>
|
|
<div style={{ backgroundColor: 'var(--l2-background)', borderStyle: 'solid', borderWidth: 1, borderColor: 'var(--l2-border)', borderRadius: 4, padding: 16 }}>
|
|
{/* Card content */}
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
**Use for:** Cards, panels, sidebars, dialogs, first-level nested containers
|
|
|
|
**Don't use for:** Deeply nested elements inside cards
|
|
|
|
### L3 - Nested Elements
|
|
|
|
Tertiary surfaces within L2 containers.
|
|
|
|
```tsx
|
|
<div style={{ backgroundColor: 'var(--l2-background)', padding: 16 }}>
|
|
<input style={{ backgroundColor: 'var(--l3-background)', borderStyle: 'solid', borderWidth: 1, borderColor: 'var(--l3-border)', borderRadius: 4, paddingInline: 12, paddingBlock: 8 }} />
|
|
</div>
|
|
```
|
|
|
|
**Use for:** Inputs, dropdowns, code blocks, elements nested inside L2 containers
|
|
|
|
### Visual Example
|
|
|
|
```
|
|
Of each level:
|
|
┌──────────────────────────────────────── L1 (Page) ──┐
|
|
│ │
|
|
│ ┌─────────────────────────────── L2 (Card) ──────┐ │
|
|
│ │ │ │
|
|
│ │ ┌───────────────── L3 (Input) ──────────────┐ │ │
|
|
│ │ │ Type here... │ │ │
|
|
│ │ └───────────────────────────────────────────┘ │ │
|
|
│ │ │ │
|
|
│ └────────────────────────────────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Hover States
|
|
|
|
Each level has corresponding hover tokens:
|
|
|
|
```tsx
|
|
<button className="demo-button">
|
|
Hover me
|
|
</button>
|
|
```
|
|
|
|
---
|
|
|
|
## Extending Tokens for New Components
|
|
|
|
When creating new components, follow this pattern to leverage the token system effectively.
|
|
|
|
### Step 1: Use Semantic Tokens as Base
|
|
|
|
Start with existing semantic tokens wherever possible:
|
|
|
|
```tsx
|
|
// dialog.tsx
|
|
function DialogContent({ children }) {
|
|
return (
|
|
<div style={{ backgroundColor: 'var(--l1-background)', borderStyle: 'solid', borderWidth: 1, borderColor: 'var(--l2-border)', borderRadius: 4, boxShadow: '0 0 #0000, 0 0 #0000, 0 0 #0000, 0 0 #0000, 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a' }}>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Step 2: Define Component-Specific Variables (When Needed)
|
|
|
|
For component-specific styling that doesn't fit existing tokens, define CSS custom properties:
|
|
|
|
```css
|
|
/* dialog/index.css */
|
|
.dialog {
|
|
--dialog-border: var(--l2-border);
|
|
--dialog-close-icon: var(--l2-foreground);
|
|
}
|
|
|
|
.alert-dialog {
|
|
--dialog-border: var(--danger-background);
|
|
}
|
|
```
|
|
|
|
### Step 3: Use Component Variables in Styles
|
|
|
|
```tsx
|
|
function DialogHeader({ className, ...props }) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'border-b border-[var(--dialog-border)] px-4 py-3',
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Real Example: Dialog Component
|
|
|
|
Here's how the Dialog component from `@signozhq/ui` uses tokens:
|
|
|
|
```tsx
|
|
// DialogContent uses surface tokens for background and border
|
|
<DialogPrimitive.Content
|
|
className={cn(
|
|
'bg-l1-background',
|
|
'border border-l2-border',
|
|
'rounded-lg shadow-[0_-4px_16px_2px_rgba(0,0,0,0.20)]',
|
|
className
|
|
)}
|
|
>
|
|
{children}
|
|
</DialogPrimitive.Content>
|
|
|
|
// DialogHeader uses component-specific variable for flexible border
|
|
<div
|
|
className={cn(
|
|
'border-b border-[var(--dialog-border)]',
|
|
'px-4 py-3',
|
|
className
|
|
)}
|
|
>
|
|
{title}
|
|
</div>
|
|
|
|
// DialogTitle uses foreground tokens
|
|
<DialogPrimitive.Title
|
|
className={cn(
|
|
'text-l1-foreground',
|
|
'text-[13px] font-medium',
|
|
className
|
|
)}
|
|
>
|
|
{children}
|
|
</DialogPrimitive.Title>
|
|
```
|
|
|
|
### Pattern Summary
|
|
|
|
1. **Background**: Use `l1-background`, `l2-background`, or `l3-background` based on nesting depth
|
|
2. **Text**: Use matching foreground tokens (`l1-foreground`, etc.)
|
|
3. **Borders**: Use level-appropriate border tokens
|
|
4. **Interactive states**: Use action tokens (`primary-background`, etc.)
|
|
5. **Component-specific**: Define CSS variables referencing semantic tokens
|
|
|
|
---
|
|
|
|
## Migration from Legacy Tokens
|
|
|
|
If you're migrating from the legacy token system, use this mapping:
|
|
|
|
| Legacy Token | New Semantic Token | Notes |
|
|
|--------------|-------------------|-------|
|
|
| `background` | `l1-background` | Page-level background |
|
|
| `foreground` | `l1-foreground` | Primary text color |
|
|
| `card` | `l2-background` | Card backgrounds |
|
|
| `card-foreground` | `l2-foreground` | Card text |
|
|
| `muted` | `l3-background` | Muted backgrounds |
|
|
| `muted-foreground` | `l3-foreground` | Muted text |
|
|
| `primary` | `primary-background` | Primary actions |
|
|
| `secondary` | `secondary-background` | Secondary actions |
|
|
| `destructive` | `danger-background` | Destructive actions |
|
|
| `accent` | `accent-primary` | Accent highlights |
|
|
| `border` | `l1-border` or `l2-border` | Context-dependent |
|
|
|
|
### Migration Example
|
|
|
|
**Before:**
|
|
```tsx
|
|
<div style={{ backgroundColor: 'var(--card)', color: 'var(--card-foreground)', borderColor: 'var(--border)' }}>
|
|
<button style={{ backgroundColor: 'var(--primary)', color: 'var(--primary-foreground)' }}>
|
|
Click
|
|
</button>
|
|
</div>
|
|
```
|
|
|
|
**After:**
|
|
```tsx
|
|
<div style={{ backgroundColor: 'var(--l2-background)', color: 'var(--l2-foreground)', borderColor: 'var(--l2-border)' }}>
|
|
<button style={{ backgroundColor: 'var(--primary-background)', color: 'var(--primary-foreground)' }}>
|
|
Click
|
|
</button>
|
|
</div>
|
|
```
|