@emeryld/ui
v0.2.7
Published
A React UI components package with provider-first theming.
Readme
@emeryld/ui
A React UI components package with provider-first theming.
Install
pnpm add @emeryld/ui react react-domQuick Start
import { ThemeProvider, Button, Text, Tray } from '@emeryld/ui'
export function App() {
return (
<ThemeProvider>
<Tray title="Demo">
<Text variant="title">Hello</Text>
<Button>Save</Button>
</Tray>
</ThemeProvider>
)
}Styling and Theming
@emeryld/ui uses CSS variables internally, but consumers style via a typed theme object.
Provider API
import { ThemeProvider, type UIThemeOverrides } from '@emeryld/ui'
const theme: UIThemeOverrides = {
'--bg': '#101318',
'--surface': '#171b21',
'--ink-primary': '#f5f7fb',
'--ink-muted': '#9fa8b8',
'--accent': '#5eb0ff',
'--radius-md': '10px',
'--font-family-sans': "'Sora', 'Segoe UI', sans-serif",
}
export function Root() {
return (
<ThemeProvider theme={theme} size={2} sizeDiff={0}>
{/* your app */}
</ThemeProvider>
)
}Before / After example
// Before
<ThemeProvider>
<Button>Primary</Button>
</ThemeProvider>
// After (customized)
<ThemeProvider
theme={{
'--accent': '#0ea5e9',
'--surface': '#0f172a',
'--ink-primary': '#e2e8f0',
'--radius-pill': '12px',
}}
>
<Button>Primary</Button>
</ThemeProvider>CSS override option (without provider)
If you prefer, you can override the same tokens in CSS:
:root {
--accent: #0ea5e9;
--surface: #0f172a;
--ink-primary: #e2e8f0;
}Available Components
Base
ListWrapperText
Interactible
- Boolean:
Boolean - Buttons:
Button,IconButton - Enum:
CyclingButton,Dropdown,PillSelector - Number:
AngleSelector,DistributionScalarEditor,NullableNumberField,NumberField,Slider - String:
Textbox(TextBoxalias)
Complex
TrayTrayFolder
Token Reference
Defaults come from defaultTheme. All keys are overridable through ThemeProvider theme={...}.
| Token | Purpose | Default |
|---|---|---|
| --bg | App/page background | #f5f5f7 |
| --surface | Base surface background | #ffffff |
| --surface-hover | Hovered surface tone | #f0f1f5 |
| --border-subtle | Subtle border color | #e2e4ea |
| --border-strong | Strong border color | #cfd3dc |
| --ink-primary | Primary text color | #111317 |
| --ink-muted | Secondary text color | #6e7480 |
| --surface-soft | Soft/secondary surface | color-mix(in srgb, var(--surface) 55%, var(--bg)) |
| --surface-raised | Raised panel surface | #ffffff |
| --surface-glass | Glass panel surface | color-mix(in srgb, var(--surface) 72%, transparent) |
| --accent | Accent/action color | #3b82f6 |
| --accent-soft | Soft accent background | color-mix(in srgb, var(--accent) 16%, transparent) |
| --focus | Focus base color | var(--accent) |
| --danger | Danger/destructive color | #e5484d |
| --display-surface | Display component surface | #1e1c1c |
| --display-dot | Display indicator color | #cbd5e1 |
| --shadow-sm | Small shadow | 0 1px 2px 0 rgb(17 24 39 / 0.04) |
| --shadow-md | Medium shadow | 0 12px 32px -14px rgb(17 24 39 / 0.16), 0 6px 12px -8px rgb(17 24 39 / 0.08) |
| --shadow-inner | Inner highlight/shadow | inset 0 1px 0 0 rgb(255 255 255 / 0.9) |
| --ring-offset-width | Focus ring offset width | 2px |
| --ring-offset-color | Focus ring offset color | var(--bg) |
| --ring-color | Focus ring glow color | var(--accent-soft) |
| --focus-ring | Full focus ring shadow stack | 0 0 0 var(--ring-offset-width) var(--ring-offset-color), 0 0 0 calc(3px + var(--ring-offset-width)) var(--ring-color) |
| --radius-sm | Small radius | 10px |
| --radius-md | Medium radius | 14px |
| --radius-lg | Large radius | 20px |
| --radius-pill | Pill radius | 9999px |
| --transition-base | Base transitions | all 0.18s cubic-bezier(0.2, 0, 0, 1) |
| --transition-smooth | Smoother/longer transitions | all 0.28s cubic-bezier(0.2, 0, 0, 1) |
| --font-family-sans | Default sans font stack | 'Inter', 'SF Pro Display', 'Avenir Next', 'Segoe UI', sans-serif |
| --font-family-display | Display font stack | 'Inter', 'SF Pro Display', 'Avenir Next', 'Segoe UI', sans-serif |
| --font-family-mono | Monospace font stack | 'IBM Plex Mono', 'SFMono-Regular', Menlo, monospace |
| --font-size-xs | XS font size | 0.75rem |
| --font-size-sm | SM font size | 0.875rem |
| --font-size-md | MD font size | 1rem |
| --font-size-lg | LG font size | 1.125rem |
| --font-size-xl | XL font size | 1.375rem |
| --font-size-2xl | 2XL font size | 1.75rem |
| --space-0 | Spacing scale 0 | 0px |
| --space-1 | Spacing scale 1 | 4px |
| --space-2 | Spacing scale 2 | 8px |
| --space-3 | Spacing scale 3 | 32px |
| --space-4 | Spacing scale 4 | 64px |
Also available for fine control: all matrix tokens (--size-font-*-* and --size-space-*-*) used by the sizing system.
API Notes
- Import everything from
@emeryld/uifor the stable public API. - Optional subpath import:
@emeryld/ui/themefor theming and size primitives.
Migration Notes (breaking cleanup)
- Root exports are now curated and explicit.
- Use
ThemeProvideras the primary way to set package styling. - React is now a peer dependency (install
reactandreact-domin the consuming app).
