@memelabui/ui 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,429 +1,427 @@
1
- # @memelabui/ui
2
-
3
- Shared UI component library for MemeLab projects. Dark-first glassmorphism design system built with React, TypeScript, and Tailwind CSS.
4
-
5
- [![npm](https://img.shields.io/npm/v/@memelabui/ui)](https://www.npmjs.com/package/@memelabui/ui)
6
-
7
- ## Install
8
-
9
- ```bash
10
- pnpm add @memelabui/ui
11
- ```
12
-
13
- Peer dependencies: `react >= 18`, `react-dom >= 18`, `tailwindcss >= 3.4`.
14
-
15
- ## Setup
16
-
17
- ### 1. Tailwind preset
18
-
19
- ```ts
20
- // tailwind.config.ts
21
- import memelabPreset from '@memelabui/ui/preset';
22
-
23
- export default {
24
- presets: [memelabPreset],
25
- content: [
26
- './src/**/*.{ts,tsx}',
27
- './node_modules/@memelabui/ui/dist/**/*.{js,mjs}',
28
- ],
29
- };
30
- ```
31
-
32
- The preset adds MemeLab colors (`primary`, `accent`, `surface`, `glow`), animations, border radius, and box shadow tokens to your Tailwind config. No component CSS is duplicated — component styles come from the CSS import below.
33
-
34
- ### 2. Import styles
35
-
36
- ```ts
37
- // main.tsx (before your app code)
38
- import '@memelabui/ui/styles';
39
- ```
40
-
41
- This imports base styles, CSS variables (`--ml-*` tokens), glassmorphism utility classes, and component animations. Must be imported once at the root of your app.
42
-
43
- ### 3. Use components
44
-
45
- ```tsx
46
- import { Button, Card, Input, ToastProvider } from '@memelabui/ui';
47
-
48
- function App() {
49
- return (
50
- <ToastProvider>
51
- <Card variant="glass" hoverable>
52
- <h2 className="section-title">Login</h2>
53
- <Input label="Email" placeholder="you@example.com" />
54
- <Button variant="primary" className="mt-4">Submit</Button>
55
- </Card>
56
- </ToastProvider>
57
- );
58
- }
59
- ```
60
-
61
- ---
62
-
63
- ## CSS Utility Classes
64
-
65
- These classes are available globally after importing `@memelabui/ui/styles`. They provide the MemeLab visual foundation.
66
-
67
- | Class | Purpose | When to use |
68
- |-------|---------|-------------|
69
- | `.glass` | Glassmorphism panel — translucent `bg`, `backdrop-filter: blur(16px)`, inset border, rounded | Visual shell for containers. **Does not include padding** — use `Card` component for padded cards |
70
- | `.surface` | Surface panelslightly more opaque `bg`, `blur(12px)`, border shadow | Alternative to `.glass` with stronger background. Also **no padding** |
71
- | `.surface-hover` | Hover elevation transitionadds `box-shadow` on hover | Pair with `.glass` or `.surface` for interactive cards |
72
- | `.section-title` | Card section heading `font-semibold`, `border-bottom`, `mb-4` | Use inside `Card` for titled sections (settings, forms) |
73
- | `.text-gradient` | Gradient text (violet to pink) | Branding, hero headings |
74
- | `.animated-gradient` | Animated gradient background | Decorative elements, loading placeholders |
75
- | `.page-container` | Centered max-w-80rem container with responsive padding | Page-level wrapper |
76
- | `.orb` / `.orb-purple` / `.orb-blue` / `.orb-pink` | Decorative blurred orbs | Background effects (see `PageShell`) |
77
- | `.pb-safe` / `.pt-safe` | iOS safe area padding | Mobile bottom/top bars |
78
- | `.no-scrollbar` | Hides scrollbar | Horizontal scroll areas, custom scrolling |
79
- | `.link-soft` | Subtle underline link | Secondary navigation links |
80
-
81
- ### Important: `.glass` / `.surface` vs `Card`
82
-
83
- The `.glass` and `.surface` CSS classes are **visual treatments only** — they add background, blur, border, and shadow. They intentionally do **not** include padding because they're used across diverse elements (headers, sidebars, modals, custom layouts).
84
-
85
- **For content cards, always use the `Card` component** instead of raw `.glass`/`.surface` classes. `Card` provides built-in padding (`p-5` by default) plus correct ARIA semantics.
86
-
87
- ```tsx
88
- // Correct — Card handles padding automatically
89
- <Card variant="glass" hoverable>
90
- <h2 className="section-title">Settings</h2>
91
- <Input label="Name" />
92
- </Card>
93
-
94
- // Avoid raw classes require manual padding
95
- <div className="glass surface-hover p-5">
96
- <h2 className="section-title">Settings</h2>
97
- <Input label="Name" />
98
- </div>
99
- ```
100
-
101
- ---
102
-
103
- ## Components
104
-
105
- ### Cards & Containers
106
-
107
- Use these to wrap content sections. Each has different levels of structure.
108
-
109
- | Component | When to use | Key props |
110
- |-----------|-------------|-----------|
111
- | `Card` | Generic content container with glassmorphism | `variant` (`'surface'` / `'glass'`), `hoverable`, `padding` (`'none'` / `'sm'` / `'md'` / `'lg'`) |
112
- | `SectionCard` | Settings/config section with title, description, and optional right slot | `title`, `description?`, `right?`, `overlay?` |
113
- | `StatCard` | Dashboard metric tile with value, label, icon, and trend | `value`, `label`, `icon?`, `trend?` |
114
- | `CollapsibleSection` | Expandable/collapsible content block | `title`, `defaultOpen?` |
115
-
116
- **Choosing the right card:**
117
-
118
- - Building a **settings form section** (title + form fields)? Use `SectionCard`
119
- - Showing a **dashboard metric** (number + label + icon)? Use `StatCard`
120
- - Need a **generic container** with glass/surface styling? Use `Card`
121
- - Need an **expandable block**? Use `CollapsibleSection`
122
-
123
- ```tsx
124
- // Settings page section
125
- <SectionCard title="AI Provider" description="Choose the AI model for your bot">
126
- <Select label="Provider" />
127
- <Input label="Model" placeholder="Default" />
128
- </SectionCard>
129
-
130
- // Dashboard metric
131
- <StatCard value="1,234" label="Messages today" trend={{ value: 12, direction: 'up' }} />
132
-
133
- // Generic glass card
134
- <Card variant="glass" hoverable padding="lg">
135
- <p>Any content here</p>
136
- </Card>
137
- ```
138
-
139
- ### Form Inputs
140
-
141
- All form components accept `label`, `error`, and `helperText` props with automatic ARIA linkage (`aria-invalid`, `aria-describedby`). They use `forwardRef` for ref forwarding and spread all native HTML attributes.
142
-
143
- | Component | When to use | Key props |
144
- |-----------|-------------|-----------|
145
- | `Input` | Single-line text input | `label?`, `error?`, `helperText?`, `hasError?` + all `<input>` attrs |
146
- | `SearchInput` | Search field with icon and clear button | `onClear?` + all `Input` props |
147
- | `Textarea` | Multi-line text input | `label?`, `error?` + all `<textarea>` attrs |
148
- | `Select` | Native dropdown select | `label?`, `error?` + all `<select>` attrs |
149
- | `Combobox` | Searchable select with keyboard navigation | `options`, `value`, `onChange`, `placeholder?` |
150
- | `Checkbox` | Checkbox with label and indeterminate support | `label?`, `indeterminate?`, `checked`, `onChange` |
151
- | `RadioGroup` / `RadioItem` | Radio button group | `value`, `onChange` on Group; `value`, `label` on Item |
152
- | `Toggle` | On/off switch | `checked`, `onChange(boolean)`, `label?`, `busy?`, `size?` |
153
- | `Slider` | Range slider with value display | `min`, `max`, `value`, `onChange` |
154
- | `TagInput` | Tag input with Enter/comma/paste support | `value: string[]`, `onChange`, `maxTags?` |
155
- | `ColorInput` | Hex color picker with swatch | `value`, `onChange` |
156
- | `FormField` | Generic wrapper for any input (label + error + helper) | `label`, `error?`, `helperText?`, `children` |
157
-
158
- ```tsx
159
- // Full form with Toggle + Input + Select
160
- <Card variant="glass" hoverable>
161
- <h2 className="section-title">Bot Personality</h2>
162
- <Input label="Bot name" value="MemeBot" />
163
- <Textarea label="Personality" placeholder="Friendly, humorous..." />
164
- <Select label="Response style">
165
- <option value="concise">Concise</option>
166
- <option value="detailed">Detailed</option>
167
- </Select>
168
- <Toggle
169
- label="Respond to @mentions"
170
- checked={mentionEnabled}
171
- onChange={setMentionEnabled}
172
- />
173
- </Card>
174
- ```
175
-
176
- ### Buttons
177
-
178
- | Component | When to use | Key props |
179
- |-----------|-------------|-----------|
180
- | `Button` | Primary actions, form submits, navigation | `variant` (`'primary'` / `'secondary'` / `'danger'` / `'success'` / `'warning'` / `'ghost'`), `loading?`, `size?` |
181
- | `IconButton` | Icon-only actions (close, menu, refresh) | `aria-label` (required), `variant?`, `size?` |
182
- | `ProgressButton` | Button with shimmer loading state | `loading?`, `progress?` |
183
-
184
- ### Data Display
185
-
186
- | Component | When to use | Key props |
187
- |-----------|-------------|-----------|
188
- | `Badge` / `Pill` | Status labels, tags, categories | `variant` (`'neutral'` / `'primary'` / `'success'` / `'danger'` / `'warning'` / `'accent'` / `'successSolid'` / `'dangerSolid'`), `size?` |
189
- | `Table` / `TableHeader` / `TableBody` / `TableRow` / `TableHead` / `TableCell` | Data tables | Compound — compose like native `<table>` |
190
- | `Tabs` / `TabList` / `Tab` / `TabPanel` | Tabbed content switching | `variant` (`'underline'` / `'pill'`); compound pattern |
191
- | `EmptyState` | Empty content placeholder | `icon?`, `title`, `description?`, `action?` |
192
- | `Skeleton` | Loading placeholder | `width?`, `height?`, `rounded?` |
193
- | `Spinner` | Loading indicator | `size` (`'sm'` / `'md'` / `'lg'`) |
194
- | `Avatar` | User avatar with fallback | `src?`, `name?`, `size?` |
195
- | `Divider` | Separator line | `orientation?`, `label?` |
196
- | `ActiveFilterPills` | Filter pill bar with clear-all | `filters`, `onRemove`, `onClearAll` |
197
- | `DotIndicator` | Remaining count dots | `count`, `max?` |
198
-
199
- ### Navigation
200
-
201
- | Component | When to use | Key props |
202
- |-----------|-------------|-----------|
203
- | `Pagination` | Page navigation | `page`, `totalPages`, `onChange` |
204
- | `Stepper` | Multi-step wizard indicator | `steps`, `currentStep` |
205
- | `Breadcrumbs` | Breadcrumb path | `items` (links/buttons) |
206
-
207
- ### Overlay & Popups
208
-
209
- | Component | When to use | Key props |
210
- |-----------|-------------|-----------|
211
- | `Modal` | Dialog / fullscreen overlay | `open`, `onClose`, children |
212
- | `ConfirmDialog` | Confirmation prompts (delete, discard) | `open`, `onConfirm`, `onCancel`, `title`, `description` |
213
- | `Tooltip` | Hover/focus info text | `content`, `children` (trigger) |
214
- | `Dropdown` | Dropdown menu (context menu, actions) | Compound: `DropdownTrigger` + `DropdownMenu` + `DropdownItem` + `DropdownSeparator` |
215
- | `Popover` | Click-triggered popup | `trigger`, `children` (content) |
216
- | `Drawer` | Slide-in side panel | `open`, `onClose`, `position` (`'left'` / `'right'` / `'bottom'`) |
217
- | `MutationOverlay` | Saving/saved/error status indicator | `status` (`'idle'` / `'saving'` / `'saved'` / `'error'`) |
218
- | `NotificationBell` | Notification button with badge | `count`, `onClick` |
219
-
220
- ### Progress & Status
221
-
222
- | Component | When to use | Key props |
223
- |-----------|-------------|-----------|
224
- | `ProgressBar` | Linear progress indicator | `value`, `max?`, `variant?`, `size?` |
225
- | `CooldownRing` | Circular countdown timer | `remaining`, `total` |
226
- | `StageProgress` | Multi-stage process tracker | `stages`, `currentStage` |
227
-
228
- ### Typography
229
-
230
- | Component | When to use | Key props |
231
- |-----------|-------------|-----------|
232
- | `Heading` | Section headings h1-h6 | `as` (`'h1'` - `'h6'`), `size?`, `gradient?` |
233
- | `Text` | Body text, captions, labels | `as` (`'p'` / `'span'`), `size?`, `color?`, `weight?`, `truncate?` |
234
-
235
- ### Layout
236
-
237
- These components provide the overall page structure. Use them together for full-page layouts.
238
-
239
- | Component | When to use | Key props |
240
- |-----------|-------------|-----------|
241
- | `PageShell` | Page wrapper with animated gradient orbs | `children` |
242
- | `DashboardLayout` | Full dashboard (navbar + sidebar + content) | `navbar`, `sidebar`, `children` |
243
- | `Navbar` | Fixed top navigation bar with glass effect | `logo?`, `children` (right-side content), `glass?` |
244
- | `Sidebar` | Collapsible side navigation | `collapsed?`, `onToggle?`, `children` (nav items) |
245
- | `Stack` | Flex container | `direction?`, `gap?`, `align?`, `justify?` |
246
- | `ScrollArea` | Scrollable container with styled scrollbar | `children` |
247
-
248
- **Full page layout example:**
249
-
250
- ```tsx
251
- import { PageShell, DashboardLayout, Navbar, Sidebar, Card } from '@memelabui/ui';
252
-
253
- function App() {
254
- return (
255
- <PageShell>
256
- <DashboardLayout
257
- navbar={
258
- <Navbar logo={<span className="text-gradient font-bold">MyApp</span>}>
259
- <Button variant="ghost">Sign out</Button>
260
- </Navbar>
261
- }
262
- sidebar={
263
- <Sidebar>
264
- <a href="/dashboard" className="px-4 py-2.5 rounded-lg text-sm text-white/60 hover:text-white">
265
- Overview
266
- </a>
267
- <a href="/settings" className="px-4 py-2.5 rounded-lg text-sm bg-accent/20 text-accent">
268
- Settings
269
- </a>
270
- </Sidebar>
271
- }
272
- >
273
- <Card variant="glass" hoverable>
274
- <h2 className="section-title">Settings</h2>
275
- <Input label="Bot name" />
276
- </Card>
277
- </DashboardLayout>
278
- </PageShell>
279
- );
280
- }
281
- ```
282
-
283
- ### Feedback
284
-
285
- | Component | When to use | Key props |
286
- |-----------|-------------|-----------|
287
- | `ToastProvider` / `useToast` | Toast notifications (wrap app root in Provider) | `useToast()` returns `{ toast }` function |
288
- | `Alert` | Inline notification banner | `variant` (`'info'` / `'success'` / `'warning'` / `'error'`), `title?`, `children` |
289
- | `CopyField` | Read-only field with copy button | `value`, `masked?` |
290
- | `Transition` | Enter/exit animations | `show`, `preset` (`'fade'` / `'scale'` / `'slide'`) |
291
-
292
- ### Accessibility
293
-
294
- | Component | When to use |
295
- |-----------|-------------|
296
- | `VisuallyHidden` | Screen reader-only text (hidden visually but accessible) |
297
-
298
- ### Hooks
299
-
300
- | Hook | When to use | Returns |
301
- |------|-------------|---------|
302
- | `useClipboard` | Copy text with status feedback | `{ copy, copied }` |
303
- | `useDisclosure` | Toggle open/close state for modals, menus | `{ isOpen, onOpen, onClose, onToggle }` |
304
- | `useMediaQuery` | Respond to viewport changes | `boolean` |
305
- | `useDebounce` | Debounce fast-changing values (search, resize) | debounced value |
306
- | `useHotkeys` | Global keyboard shortcuts | bind key combos to callbacks |
307
- | `useIntersectionObserver` | Lazy loading, infinite scroll | `{ ref, isIntersecting }` |
308
- | `useSharedNow` | Live clock for "X ago" labels, countdowns | `Date` that updates every N ms |
309
-
310
- ---
311
-
312
- ## Common Patterns
313
-
314
- ### Settings page with sections
315
-
316
- ```tsx
317
- import { Card, Input, Textarea, Select, Toggle } from '@memelabui/ui';
318
-
319
- function SettingsPage() {
320
- return (
321
- <div className="space-y-6">
322
- <Card variant="glass" hoverable>
323
- <h2 className="section-title">Bot Personality</h2>
324
- <div className="space-y-4">
325
- <Input label="Bot name" value={name} onChange={...} />
326
- <Textarea label="Personality description" value={desc} onChange={...} />
327
- <div className="grid grid-cols-3 gap-4">
328
- <Select label="Style"><option>Concise</option></Select>
329
- <Select label="Language"><option>Auto</option></Select>
330
- <Input label="Max length" type="number" />
331
- </div>
332
- </div>
333
- </Card>
334
-
335
- <Card variant="glass" hoverable>
336
- <h2 className="section-title">Triggers</h2>
337
- <div className="space-y-3">
338
- <Toggle label="Respond to @mentions" checked={...} onChange={...} />
339
- <Toggle label="Respond to keywords" checked={...} onChange={...} />
340
- <TagInput value={keywords} onChange={...} placeholder="Add keyword" />
341
- </div>
342
- </Card>
343
- </div>
344
- );
345
- }
346
- ```
347
-
348
- ### Dashboard with stats
349
-
350
- ```tsx
351
- import { StatCard, SectionCard, Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@memelabui/ui';
352
-
353
- function Dashboard() {
354
- return (
355
- <>
356
- <div className="grid grid-cols-3 gap-4 mb-6">
357
- <StatCard value="1,234" label="Messages" trend={{ value: 12, direction: 'up' }} />
358
- <StatCard value="89%" label="Response rate" />
359
- <StatCard value="2.3s" label="Avg. response" />
360
- </div>
361
-
362
- <SectionCard title="Recent Activity" description="Last 24 hours">
363
- <Table>
364
- <TableHeader>
365
- <TableRow><TableHead>Time</TableHead><TableHead>Message</TableHead></TableRow>
366
- </TableHeader>
367
- <TableBody>
368
- <TableRow><TableCell>12:30</TableCell><TableCell>Hello bot!</TableCell></TableRow>
369
- </TableBody>
370
- </Table>
371
- </SectionCard>
372
- </>
373
- );
374
- }
375
- ```
376
-
377
- ---
378
-
379
- ## Customization
380
-
381
- Override CSS variables to customize the theme. Values must be **space-separated RGB channels** (not hex) for Tailwind opacity support:
382
-
383
- ```css
384
- :root {
385
- --ml-bg: 10 10 15; /* Page background */
386
- --ml-primary: 139 92 246; /* Primary color (buttons, toggles, active states) */
387
- --ml-accent: 102 126 234; /* Accent / gradient start */
388
- --ml-glow-purple: 118 75 162; /* Gradient middle */
389
- --ml-glow-pink: 240 147 251; /* Gradient end */
390
- --ml-surface-50: 20 20 32; /* Surface tint */
391
- --ml-surface-100: 30 30 48; /* Surface tint darker */
392
- }
393
- ```
394
-
395
- Additional tokens:
396
-
397
- | Token | Default | Purpose |
398
- |-------|---------|---------|
399
- | `--ml-glass-bg` | `rgba(255,255,255,0.05)` | Glass panel background |
400
- | `--ml-glass-blur` | `16px` | Glass backdrop blur |
401
- | `--ml-glass-border` | `rgba(255,255,255,0.1)` | Glass inset border |
402
- | `--ml-radius-md` | `0.75rem` | Default border radius |
403
- | `--ml-font-sans` | System font stack | Base font family |
404
- | `--ml-transition-fast` | `150ms ease` | Hover/focus transition speed |
405
-
406
- ## Features
407
-
408
- - **Dark-first glassmorphism** design system
409
- - **Zero runtime dependencies** — only peer deps (react, react-dom, tailwindcss)
410
- - **Tree-shakeable** — each component independently importable
411
- - **Fully accessible** — ARIA attributes, keyboard navigation, focus management, `prefers-reduced-motion` support
412
- - **SSR-safe** — no `document`/`window` access during server render
413
- - **TypeScript-first** all components and hooks fully typed with exported types
414
- - **Tailwind preset** tokens, colors, and animations included
415
-
416
- ## Development
417
-
418
- ```bash
419
- pnpm dev # Storybook on :6006
420
- pnpm build # Build package (tsup + postcss)
421
- pnpm test # Run tests (vitest watch)
422
- pnpm test:ci # Run tests once
423
- pnpm typecheck # TypeScript check
424
- pnpm lint # ESLint
425
- ```
426
-
427
- ## License
428
-
429
- MIT
1
+ # @memelabui/ui
2
+
3
+ Shared UI component library for MemeLab projects. Dark-first glassmorphism design system built with React, TypeScript, and Tailwind CSS.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@memelabui/ui)](https://www.npmjs.com/package/@memelabui/ui)
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add @memelabui/ui
11
+ ```
12
+
13
+ Peer dependencies: `react >= 18`, `react-dom >= 18`, `tailwindcss >= 3.4`.
14
+
15
+ ## Setup
16
+
17
+ ### 1. Tailwind preset
18
+
19
+ ```ts
20
+ // tailwind.config.ts
21
+ import memelabPreset from '@memelabui/ui/preset';
22
+
23
+ export default {
24
+ presets: [memelabPreset],
25
+ content: ['./src/**/*.{ts,tsx}', './node_modules/@memelabui/ui/dist/**/*.{js,mjs}'],
26
+ };
27
+ ```
28
+
29
+ The preset adds MemeLab colors (`primary`, `accent`, `surface`, `glow`), animations, border radius, and box shadow tokens to your Tailwind config. No component CSS is duplicated — component styles come from the CSS import below.
30
+
31
+ ### 2. Import styles
32
+
33
+ ```ts
34
+ // main.tsx (before your app code)
35
+ import '@memelabui/ui/styles';
36
+ ```
37
+
38
+ This imports base styles, CSS variables (`--ml-*` tokens), glassmorphism utility classes, and component animations. Must be imported once at the root of your app.
39
+
40
+ ### 3. Use components
41
+
42
+ ```tsx
43
+ import { Button, Card, Input, ToastProvider } from '@memelabui/ui';
44
+
45
+ function App() {
46
+ return (
47
+ <ToastProvider>
48
+ <Card variant="glass" hoverable>
49
+ <h2 className="section-title">Login</h2>
50
+ <Input label="Email" placeholder="you@example.com" />
51
+ <Button variant="primary" className="mt-4">
52
+ Submit
53
+ </Button>
54
+ </Card>
55
+ </ToastProvider>
56
+ );
57
+ }
58
+ ```
59
+
60
+ ---
61
+
62
+ ## CSS Utility Classes
63
+
64
+ These classes are available globally after importing `@memelabui/ui/styles`. They provide the MemeLab visual foundation.
65
+
66
+ | Class | Purpose | When to use |
67
+ | -------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
68
+ | `.glass` | Glassmorphism panel — translucent `bg`, `backdrop-filter: blur(16px)`, inset border, rounded | Visual shell for containers. **Does not include padding** — use `Card` component for padded cards |
69
+ | `.surface` | Surface panel — slightly more opaque `bg`, `blur(12px)`, border shadow | Alternative to `.glass` with stronger background. Also **no padding** |
70
+ | `.surface-hover` | Hover elevation transition adds `box-shadow` on hover | Pair with `.glass` or `.surface` for interactive cards |
71
+ | `.section-title` | Card section heading`font-semibold`, `border-bottom`, `mb-4` | Use inside `Card` for titled sections (settings, forms) |
72
+ | `.text-gradient` | Gradient text (violet to pink) | Branding, hero headings |
73
+ | `.animated-gradient` | Animated gradient background | Decorative elements, loading placeholders |
74
+ | `.page-container` | Centered max-w-80rem container with responsive padding | Page-level wrapper |
75
+ | `.orb` / `.orb-purple` / `.orb-blue` / `.orb-pink` | Decorative blurred orbs | Background effects (see `PageShell`) |
76
+ | `.pb-safe` / `.pt-safe` | iOS safe area padding | Mobile bottom/top bars |
77
+ | `.no-scrollbar` | Hides scrollbar | Horizontal scroll areas, custom scrolling |
78
+ | `.link-soft` | Subtle underline link | Secondary navigation links |
79
+
80
+ ### Important: `.glass` / `.surface` vs `Card`
81
+
82
+ The `.glass` and `.surface` CSS classes are **visual treatments only** — they add background, blur, border, and shadow. They intentionally do **not** include padding because they're used across diverse elements (headers, sidebars, modals, custom layouts).
83
+
84
+ **For content cards, always use the `Card` component** instead of raw `.glass`/`.surface` classes. `Card` provides built-in padding (`p-5` by default) plus correct ARIA semantics.
85
+
86
+ ```tsx
87
+ // Correct — Card handles padding automatically
88
+ <Card variant="glass" hoverable>
89
+ <h2 className="section-title">Settings</h2>
90
+ <Input label="Name" />
91
+ </Card>
92
+
93
+ // Avoid — raw classes require manual padding
94
+ <div className="glass surface-hover p-5">
95
+ <h2 className="section-title">Settings</h2>
96
+ <Input label="Name" />
97
+ </div>
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Components
103
+
104
+ ### Cards & Containers
105
+
106
+ Use these to wrap content sections. Each has different levels of structure.
107
+
108
+ | Component | When to use | Key props |
109
+ | -------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
110
+ | `Card` | Generic content container with glassmorphism | `variant` (`'surface'` / `'glass'`), `hoverable`, `padding` (`'none'` / `'sm'` / `'md'` / `'lg'`) |
111
+ | `SectionCard` | Settings/config section with title, description, and optional right slot | `title`, `description?`, `right?`, `overlay?` |
112
+ | `StatCard` | Dashboard metric tile with clickable, compact, and compound variants | `value`, `label`, `icon?`, `trend?`, `size?`, `secondaryMetric?`, `href?`, `loading?` |
113
+ | `CollapsibleSection` | Expandable/collapsible content block | `title`, `defaultOpen?` |
114
+
115
+ **Choosing the right card:**
116
+
117
+ - Building a **settings form section** (title + form fields)? Use `SectionCard`
118
+ - Showing a **dashboard metric** (number + label + icon)? Use `StatCard`
119
+ - Need a **generic container** with glass/surface styling? Use `Card`
120
+ - Need an **expandable block**? Use `CollapsibleSection`
121
+
122
+ ```tsx
123
+ // Settings page section
124
+ <SectionCard title="AI Provider" description="Choose the AI model for your bot">
125
+ <Select label="Provider" />
126
+ <Input label="Model" placeholder="Default" />
127
+ </SectionCard>
128
+
129
+ // Dashboard metric
130
+ <StatCard value="1,234" label="Messages today" trend={{ value: 12, label: 'vs last week' }} />
131
+
132
+ // Generic glass card
133
+ <Card variant="glass" hoverable padding="lg">
134
+ <p>Any content here</p>
135
+ </Card>
136
+ ```
137
+
138
+ ### Form Inputs
139
+
140
+ All form components accept `label`, `error`, and `helperText` props with automatic ARIA linkage (`aria-invalid`, `aria-describedby`). They use `forwardRef` for ref forwarding and spread all native HTML attributes.
141
+
142
+ | Component | When to use | Key props |
143
+ | -------------------------- | ------------------------------------------------------ | -------------------------------------------------------------------- |
144
+ | `Input` | Single-line text input | `label?`, `error?`, `helperText?`, `hasError?` + all `<input>` attrs |
145
+ | `SearchInput` | Search field with icon and clear button | `onClear?` + all `Input` props |
146
+ | `DateRangePicker` | Date range input with presets, calendar popover, and mobile drawer | `value`, `onChange`, `presets?`, `maxRangeDays?`, `compact?` |
147
+ | `Textarea` | Multi-line text input | `label?`, `error?` + all `<textarea>` attrs |
148
+ | `Select` | Native dropdown select | `label?`, `error?` + all `<select>` attrs |
149
+ | `Combobox` | Searchable select with keyboard navigation | `options`, `value`, `onChange`, `placeholder?` |
150
+ | `Checkbox` | Checkbox with label and indeterminate support | `label?`, `indeterminate?`, `checked`, `onChange` |
151
+ | `RadioGroup` / `RadioItem` | Radio button group | `value`, `onChange` on Group; `value`, `label` on Item |
152
+ | `Toggle` | On/off switch | `checked`, `onChange(boolean)`, `label?`, `busy?`, `size?` |
153
+ | `Slider` | Range slider with value display | `min`, `max`, `value`, `onChange` |
154
+ | `TagInput` | Tag input with Enter/comma/paste support | `value: string[]`, `onChange`, `maxTags?` |
155
+ | `ColorInput` | Hex color picker with swatch | `value`, `onChange` |
156
+ | `FormField` | Generic wrapper for any input (label + error + helper) | `label`, `error?`, `helperText?`, `children` |
157
+
158
+ ```tsx
159
+ // Full form with Toggle + Input + Select
160
+ <Card variant="glass" hoverable>
161
+ <h2 className="section-title">Bot Personality</h2>
162
+ <Input label="Bot name" value="MemeBot" />
163
+ <Textarea label="Personality" placeholder="Friendly, humorous..." />
164
+ <Select label="Response style">
165
+ <option value="concise">Concise</option>
166
+ <option value="detailed">Detailed</option>
167
+ </Select>
168
+ <Toggle label="Respond to @mentions" checked={mentionEnabled} onChange={setMentionEnabled} />
169
+ </Card>
170
+ ```
171
+
172
+ ### Buttons
173
+
174
+ | Component | When to use | Key props |
175
+ | ---------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
176
+ | `Button` | Primary actions, form submits, navigation | `variant` (`'primary'` / `'secondary'` / `'danger'` / `'success'` / `'warning'` / `'ghost'`), `loading?`, `size?` |
177
+ | `IconButton` | Icon-only actions (close, menu, refresh) | `aria-label` (required), `variant?`, `size?` |
178
+ | `ProgressButton` | Button with shimmer loading state | `loading?`, `progress?` |
179
+
180
+ ### Data Display
181
+
182
+ | Component | When to use | Key props |
183
+ | ------------------------------------------------------------------------------ | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
184
+ | `Badge` / `Pill` | Status labels, tags, categories | `variant` (`'neutral'` / `'primary'` / `'success'` / `'danger'` / `'warning'` / `'accent'` / `'successSolid'` / `'dangerSolid'`), `size?` |
185
+ | `Table` / `TableHeader` / `TableBody` / `TableRow` / `TableHead` / `TableCell` | Table primitives | Compound — compose like native `<table>` |
186
+ | `DataTable` | CMS tables with sorting, filters, search, and pagination | `data`, `columns`, `filters?`, `sortBy?`, `page?`, `pageSize?`, `loading?` |
187
+ | `Timeline` | Activity history, audits, and event feeds | `events`, `groupBy?`, `order?`, `timestampPosition?`, `maxVisible?` |
188
+ | `Tabs` / `TabList` / `Tab` / `TabPanel` | Tabbed content switching | `variant` (`'underline'` / `'pill'`); compound pattern |
189
+ | `EmptyState` | Empty content placeholder | `icon?`, `title`, `description?`, `action?` |
190
+ | `Skeleton` | Loading placeholder | `width?`, `height?`, `rounded?` |
191
+ | `Spinner` | Loading indicator | `size` (`'sm'` / `'md'` / `'lg'`) |
192
+ | `Avatar` | User avatar with fallback | `src?`, `name?`, `size?` |
193
+ | `Divider` | Separator line | `orientation?`, `label?` |
194
+ | `ActiveFilterPills` | Filter pill bar with clear-all | `filters`, `onRemove`, `onClearAll` |
195
+ | `DotIndicator` | Remaining count dots | `count`, `max?` |
196
+
197
+ ### Navigation
198
+
199
+ | Component | When to use | Key props |
200
+ | ------------- | --------------------------- | -------------------------------- |
201
+ | `Pagination` | Page navigation | `page`, `totalPages`, `onPageChange` |
202
+ | `Stepper` | Multi-step wizard indicator | `steps`, `activeStep` |
203
+ | `Breadcrumbs` | Breadcrumb path with collapse support | `items`, `maxItems?`, `renderLink?`, `separator?` |
204
+
205
+ ### Overlay & Popups
206
+
207
+ | Component | When to use | Key props |
208
+ | ------------------ | -------------------------------------- | ----------------------------------------------------------------------------------- |
209
+ | `Modal` | Dialog / fullscreen overlay | `isOpen`, `onClose`, `children` |
210
+ | `ConfirmDialog` | Confirmation prompts (delete, discard) | `isOpen`, `onConfirm`, `onClose`, `title`, `message` |
211
+ | `Tooltip` | Hover/focus info text | `content`, `children` (trigger) |
212
+ | `Dropdown` | Dropdown menu (context menu, actions) | Compound: `DropdownTrigger` + `DropdownMenu` + `DropdownItem` + `DropdownSeparator` |
213
+ | `Popover` | Click-triggered popup | `trigger`, `children` (content) |
214
+ | `Drawer` | Slide-in side panel | `open`, `onClose`, `position` (`'left'` / `'right'` / `'bottom'`) |
215
+ | `MutationOverlay` | Saving/saved/error status indicator | `status` (`'idle'` / `'saving'` / `'saved'` / `'error'`) |
216
+ | `NotificationBell` | Notification button with badge | `count`, `onClick` |
217
+
218
+ ### Progress & Status
219
+
220
+ | Component | When to use | Key props |
221
+ | --------------- | --------------------------- | ------------------------------------ |
222
+ | `ProgressBar` | Linear progress indicator | `value`, `max?`, `variant?`, `size?` |
223
+ | `CooldownRing` | Circular countdown timer | `remaining`, `total` |
224
+ | `StageProgress` | Multi-stage process tracker | `stages`, `currentStage` |
225
+
226
+ ### Typography
227
+
228
+ | Component | When to use | Key props |
229
+ | --------- | --------------------------- | ------------------------------------------------------------------ |
230
+ | `Heading` | Section headings h1-h6 | `as` (`'h1'` - `'h6'`), `size?`, `gradient?` |
231
+ | `Text` | Body text, captions, labels | `as` (`'p'` / `'span'`), `size?`, `color?`, `weight?`, `truncate?` |
232
+
233
+ ### Layout
234
+
235
+ These components provide the overall page structure. Use them together for full-page layouts.
236
+
237
+ | Component | When to use | Key props |
238
+ | ----------------- | ------------------------------------------- | ----------------------------------------------------------------------------- |
239
+ | `PageShell` | Page wrapper with animated gradient orbs | `children` |
240
+ | `DashboardLayout` | Full dashboard layout or built-in app shell | `navbar`, `sidebar`, `children`, `brand`, `user`, `headerActions`, `navItems` |
241
+ | `Navbar` | Fixed top navigation bar with glass effect | `logo?`, `children` (right-side content), `glass?` |
242
+ | `Sidebar` | Collapsible side navigation | `collapsed?`, `onToggle?`, `children` (nav items) |
243
+ | `Stack` | Flex container | `direction?`, `gap?`, `align?`, `justify?` |
244
+ | `ScrollArea` | Scrollable container with styled scrollbar | `children` |
245
+
246
+ **Full page layout example:**
247
+
248
+ ```tsx
249
+ import { Button, Card, DashboardLayout, Input } from '@memelabui/ui';
250
+
251
+ function App() {
252
+ return (
253
+ <DashboardLayout
254
+ brand={<span className="text-gradient font-bold">MyApp</span>}
255
+ headerActions={<Button variant="ghost">Sign out</Button>}
256
+ navItems={[
257
+ { label: 'Overview', icon: '📊', href: '/dashboard', active: true },
258
+ { label: 'Settings', icon: '⚙️', href: '/settings' },
259
+ ]}
260
+ maxWidth="full"
261
+ >
262
+ <Card variant="glass" hoverable>
263
+ <h2 className="section-title">Settings</h2>
264
+ <Input label="Bot name" />
265
+ </Card>
266
+ </DashboardLayout>
267
+ );
268
+ }
269
+ ```
270
+
271
+ ### Feedback
272
+
273
+ | Component | When to use | Key props |
274
+ | ---------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------- |
275
+ | `ToastProvider` / `useToast` | Toast notifications (wrap app root in Provider) | `useToast()` returns `{ toast }` function |
276
+ | `Alert` | Inline notification banner | `variant` (`'info'` / `'success'` / `'warning'` / `'error'`), `title?`, `children` |
277
+ | `CopyField` | Read-only field with copy/reveal support | `value`, `masked?`, `description?`, `copyOnClick?`, `maskFormatter?` |
278
+ | `Transition` | Enter/exit animations | `show`, `preset` (`'fade'` / `'scale'` / `'slide'`) |
279
+
280
+ ### Accessibility
281
+
282
+ | Component | When to use |
283
+ | ---------------- | -------------------------------------------------------- |
284
+ | `VisuallyHidden` | Screen reader-only text (hidden visually but accessible) |
285
+
286
+ ### Hooks
287
+
288
+ | Hook | When to use | Returns |
289
+ | ------------------------- | ---------------------------------------------- | --------------------------------- |
290
+ | `useClipboard` | Copy text with status feedback | `{ copy, copied }` |
291
+ | `useDisclosure` | Toggle open/close state for modals, menus | `{ isOpen, open, close, toggle }` |
292
+ | `useMediaQuery` | Respond to viewport changes | `boolean` |
293
+ | `useDebounce` | Debounce fast-changing values (search, resize) | debounced value |
294
+ | `useHotkeys` | Global keyboard shortcuts | bind key combos to callbacks |
295
+ | `useIntersectionObserver` | Lazy loading, infinite scroll | `{ ref, isIntersecting }` |
296
+ | `useSharedNow` | Live clock for "X ago" labels, countdowns | `Date` that updates every N ms |
297
+
298
+ ---
299
+
300
+ ## Common Patterns
301
+
302
+ ### Settings page with sections
303
+
304
+ ```tsx
305
+ import { Card, Input, Textarea, Select, Toggle } from '@memelabui/ui';
306
+
307
+ function SettingsPage() {
308
+ return (
309
+ <div className="space-y-6">
310
+ <Card variant="glass" hoverable>
311
+ <h2 className="section-title">Bot Personality</h2>
312
+ <div className="space-y-4">
313
+ <Input label="Bot name" value={name} onChange={...} />
314
+ <Textarea label="Personality description" value={desc} onChange={...} />
315
+ <div className="grid grid-cols-3 gap-4">
316
+ <Select label="Style"><option>Concise</option></Select>
317
+ <Select label="Language"><option>Auto</option></Select>
318
+ <Input label="Max length" type="number" />
319
+ </div>
320
+ </div>
321
+ </Card>
322
+
323
+ <Card variant="glass" hoverable>
324
+ <h2 className="section-title">Triggers</h2>
325
+ <div className="space-y-3">
326
+ <Toggle label="Respond to @mentions" checked={...} onChange={...} />
327
+ <Toggle label="Respond to keywords" checked={...} onChange={...} />
328
+ <TagInput value={keywords} onChange={...} placeholder="Add keyword" />
329
+ </div>
330
+ </Card>
331
+ </div>
332
+ );
333
+ }
334
+ ```
335
+
336
+ ### Dashboard with stats
337
+
338
+ ```tsx
339
+ import { StatCard, SectionCard, Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@memelabui/ui';
340
+
341
+ function Dashboard() {
342
+ return (
343
+ <>
344
+ <div className="grid grid-cols-3 gap-4 mb-6">
345
+ <StatCard value="1,234" label="Messages" trend={{ value: 12, label: 'vs last week' }} />
346
+ <StatCard value="89%" label="Response rate" />
347
+ <StatCard value="2.3s" label="Avg. response" />
348
+ </div>
349
+
350
+ <SectionCard title="Recent Activity" description="Last 24 hours">
351
+ <Table>
352
+ <TableHeader>
353
+ <TableRow>
354
+ <TableHead>Time</TableHead>
355
+ <TableHead>Message</TableHead>
356
+ </TableRow>
357
+ </TableHeader>
358
+ <TableBody>
359
+ <TableRow>
360
+ <TableCell>12:30</TableCell>
361
+ <TableCell>Hello bot!</TableCell>
362
+ </TableRow>
363
+ </TableBody>
364
+ </Table>
365
+ </SectionCard>
366
+ </>
367
+ );
368
+ }
369
+ ```
370
+
371
+ ---
372
+
373
+ ## Customization
374
+
375
+ Override CSS variables to customize the theme. Values must be **space-separated RGB channels** (not hex) for Tailwind opacity support:
376
+
377
+ ```css
378
+ :root {
379
+ --ml-bg: 10 10 15; /* Page background */
380
+ --ml-primary: 139 92 246; /* Primary color (buttons, toggles, active states) */
381
+ --ml-accent: 102 126 234; /* Accent / gradient start */
382
+ --ml-glow-purple: 118 75 162; /* Gradient middle */
383
+ --ml-glow-pink: 240 147 251; /* Gradient end */
384
+ --ml-surface-50: 20 20 32; /* Surface tint */
385
+ --ml-surface-100: 30 30 48; /* Surface tint darker */
386
+ }
387
+ ```
388
+
389
+ Additional tokens:
390
+
391
+ | Token | Default | Purpose |
392
+ | ---------------------- | ------------------------ | ---------------------------- |
393
+ | `--ml-glass-bg` | `rgba(255,255,255,0.05)` | Glass panel background |
394
+ | `--ml-glass-blur` | `16px` | Glass backdrop blur |
395
+ | `--ml-glass-border` | `rgba(255,255,255,0.1)` | Glass inset border |
396
+ | `--ml-radius-md` | `0.75rem` | Default border radius |
397
+ | `--ml-font-sans` | System font stack | Base font family |
398
+ | `--ml-transition-fast` | `150ms ease` | Hover/focus transition speed |
399
+
400
+ ## Features
401
+
402
+ - **Dark-first glassmorphism** design system
403
+ - **Zero runtime dependencies** only peer deps (react, react-dom, tailwindcss)
404
+ - **Tree-shakeable** each component independently importable
405
+ - **Fully accessible** — ARIA attributes, keyboard navigation, focus management, `prefers-reduced-motion` support
406
+ - **SSR-safe** — no `document`/`window` access during server render
407
+ - **TypeScript-first** — all components and hooks fully typed with exported types
408
+ - **Tailwind preset** tokens, colors, and animations included
409
+
410
+ ## Development
411
+
412
+ ```bash
413
+ pnpm dev # Storybook on :6006
414
+ pnpm build # Build package (tsup + postcss)
415
+ pnpm test # Run tests (vitest watch)
416
+ pnpm test:ci # Run tests once
417
+ pnpm typecheck # TypeScript check
418
+ pnpm lint # ESLint
419
+ ```
420
+
421
+ ## License
422
+
423
+ MIT
424
+
425
+
426
+
427
+