mcp-pro-ui 1.0.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.
@@ -0,0 +1,698 @@
1
+ export const COMPONENTS = [
2
+ // ─── DATA ────────────────────────────────────────────────────────────────
3
+ {
4
+ name: 'ProTable',
5
+ importName: 'ProTable',
6
+ category: 'data',
7
+ description: 'Advanced data table with server-side pagination, sorting, filtering, column toggling, column pinning, row selection, bulk actions, and expandable rows. Supports both server-side (request) and client-side (dataSource) modes.',
8
+ useCases: [
9
+ 'admin data table',
10
+ 'CRUD list page',
11
+ 'data grid with pagination',
12
+ 'table with search/filter',
13
+ 'bulk actions table',
14
+ 'server-side pagination',
15
+ ],
16
+ props: [
17
+ { name: 'columns', type: 'ProColumnType<T>[]', required: true, description: 'Column definitions' },
18
+ { name: 'request', type: '(params: QueryParams) => Promise<RequestResult<T>>', required: false, description: 'Server-side data fetcher. Mutually exclusive with dataSource.' },
19
+ { name: 'dataSource', type: 'T[]', required: false, description: 'Client-side static data. Mutually exclusive with request.' },
20
+ { name: 'rowKey', type: 'keyof T | ((record: T) => string)', required: true, description: 'Unique key for each row' },
21
+ { name: 'headerTitle', type: 'string', required: false, description: 'Table header title' },
22
+ { name: 'toolBarRender', type: '() => ReactNode[]', required: false, description: 'Render extra buttons in the toolbar' },
23
+ { name: 'search', type: 'boolean', required: false, default: 'true', description: 'Set false to hide search form' },
24
+ { name: 'loading', type: 'boolean', required: false, description: 'Override loading state' },
25
+ { name: 'pagination', type: '{ defaultPageSize?: number; pageSizeOptions?: number[] }', required: false, description: 'Pagination config' },
26
+ { name: 'rowSelection', type: '{ onChange?: (keys: string[], rows: T[]) => void }', required: false, description: 'Enable row selection with checkboxes' },
27
+ { name: 'bulkActions', type: 'BulkActionDef<T>[]', required: false, description: 'Actions shown when rows are selected' },
28
+ { name: 'expandedRowRender', type: '(record: T) => ReactNode', required: false, description: 'Render content below expanded row' },
29
+ { name: 'rowClassName', type: '(record: T, index: number) => string', required: false, description: 'Add CSS classes to rows conditionally' },
30
+ { name: 'onRow', type: '(record: T, index: number) => { onClick?; onDoubleClick?; onContextMenu? }', required: false, description: 'Row event handlers' },
31
+ { name: 'size', type: "'sm' | 'md' | 'lg'", required: false, default: "'md'", description: 'Table density size' },
32
+ ],
33
+ example: `import { ProTable } from '@dangbt/pro-ui'
34
+ import type { ProColumnType } from '@dangbt/pro-ui'
35
+
36
+ interface User {
37
+ id: string
38
+ name: string
39
+ email: string
40
+ status: 'active' | 'inactive'
41
+ createdAt: string
42
+ }
43
+
44
+ const columns: ProColumnType<User>[] = [
45
+ { title: 'Name', dataIndex: 'name', sortable: true },
46
+ { title: 'Email', dataIndex: 'email' },
47
+ {
48
+ title: 'Status',
49
+ dataIndex: 'status',
50
+ valueType: 'select',
51
+ valueEnum: {
52
+ active: { text: 'Active', color: 'success' },
53
+ inactive: { text: 'Inactive', color: 'default' },
54
+ },
55
+ },
56
+ { title: 'Created', dataIndex: 'createdAt', valueType: 'date' },
57
+ ]
58
+
59
+ export function UsersPage() {
60
+ return (
61
+ <ProTable<User>
62
+ headerTitle="Users"
63
+ columns={columns}
64
+ rowKey="id"
65
+ request={async ({ current, pageSize, ...filters }) => {
66
+ const res = await fetch(\`/api/users?page=\${current}&limit=\${pageSize}\`)
67
+ const data = await res.json()
68
+ return { data: data.items, total: data.total, success: true }
69
+ }}
70
+ toolBarRender={() => [
71
+ <Button key="add" variant="solid" onPress={() => {}}>Add User</Button>
72
+ ]}
73
+ rowSelection={{ onChange: (keys, rows) => console.log(keys, rows) }}
74
+ bulkActions={[
75
+ { label: 'Delete selected', danger: true, onClick: (keys) => console.log('delete', keys) },
76
+ ]}
77
+ />
78
+ )
79
+ }`,
80
+ },
81
+ // ─── FORM ─────────────────────────────────────────────────────────────────
82
+ {
83
+ name: 'ProForm',
84
+ importName: 'ProForm, ProFormInput, ProFormSelect, ProFormDatePicker, ProFormTextarea, ProFormNumberField, ProFormCheckbox, ProFormSwitch, ProFormRadioGroup, ProFormComboBox, ProFormAsyncSelect',
85
+ category: 'form',
86
+ description: 'Form builder with Zod validation, grid layout, and a rich set of field components. Uses react-hook-form under the hood.',
87
+ useCases: [
88
+ 'create/edit form',
89
+ 'settings form',
90
+ 'login form',
91
+ 'form with validation',
92
+ 'multi-column form layout',
93
+ ],
94
+ props: [
95
+ { name: 'schema', type: 'ZodSchema', required: true, description: 'Zod schema for validation' },
96
+ { name: 'onSubmit', type: '(values: T) => void | Promise<void>', required: true, description: 'Submit handler with validated values' },
97
+ { name: 'defaultValues', type: 'Partial<T>', required: false, description: 'Initial form values' },
98
+ { name: 'layout', type: "'vertical' | 'horizontal'", required: false, default: "'vertical'", description: 'Label placement' },
99
+ { name: 'cols', type: 'number', required: false, default: '1', description: 'Grid columns for the form' },
100
+ { name: 'loading', type: 'boolean', required: false, description: 'Show loading state on submit button' },
101
+ { name: 'submitText', type: 'string', required: false, default: "'Submit'", description: 'Submit button label' },
102
+ { name: 'onReset', type: '() => void', required: false, description: 'Called when form resets' },
103
+ ],
104
+ example: `import { z } from 'zod'
105
+ import { ProForm, ProFormInput, ProFormSelect, ProFormDatePicker } from '@dangbt/pro-ui'
106
+
107
+ const schema = z.object({
108
+ name: z.string().min(1, 'Name is required'),
109
+ email: z.string().email('Invalid email'),
110
+ role: z.enum(['admin', 'user', 'viewer']),
111
+ joinDate: z.string().optional(),
112
+ })
113
+
114
+ type FormValues = z.infer<typeof schema>
115
+
116
+ export function CreateUserForm() {
117
+ return (
118
+ <ProForm<FormValues>
119
+ schema={schema}
120
+ onSubmit={async (values) => {
121
+ await fetch('/api/users', {
122
+ method: 'POST',
123
+ body: JSON.stringify(values),
124
+ })
125
+ }}
126
+ defaultValues={{ role: 'user' }}
127
+ cols={2}
128
+ submitText="Create User"
129
+ >
130
+ <ProFormInput name="name" label="Full Name" placeholder="John Doe" />
131
+ <ProFormInput name="email" label="Email" type="email" />
132
+ <ProFormSelect
133
+ name="role"
134
+ label="Role"
135
+ options={[
136
+ { value: 'admin', label: 'Admin' },
137
+ { value: 'user', label: 'User' },
138
+ { value: 'viewer', label: 'Viewer' },
139
+ ]}
140
+ />
141
+ <ProFormDatePicker name="joinDate" label="Join Date" />
142
+ </ProForm>
143
+ )
144
+ }`,
145
+ },
146
+ // ─── LAYOUT ───────────────────────────────────────────────────────────────
147
+ {
148
+ name: 'Layout',
149
+ importName: 'Layout',
150
+ category: 'layout',
151
+ description: 'App shell with collapsible sidebar navigation, header slot, and content area. Handles responsive mobile drawer automatically.',
152
+ useCases: [
153
+ 'admin app shell',
154
+ 'dashboard layout',
155
+ 'sidebar navigation',
156
+ 'app with header and sidebar',
157
+ ],
158
+ props: [
159
+ { name: 'nav', type: 'NavItem[]', required: true, description: 'Navigation items for the sidebar' },
160
+ { name: 'header', type: 'ReactNode', required: false, description: 'Header content (right side)' },
161
+ { name: 'logo', type: 'ReactNode', required: false, description: 'Logo in the sidebar' },
162
+ { name: 'children', type: 'ReactNode', required: true, description: 'Page content' },
163
+ ],
164
+ example: `import { Layout } from '@dangbt/pro-ui'
165
+ import { LayoutDashboard, Users, Settings } from 'lucide-react'
166
+
167
+ const nav = [
168
+ { label: 'Dashboard', href: '/', icon: <LayoutDashboard size={16} /> },
169
+ { label: 'Users', href: '/users', icon: <Users size={16} /> },
170
+ { label: 'Settings', href: '/settings', icon: <Settings size={16} /> },
171
+ ]
172
+
173
+ export function App() {
174
+ return (
175
+ <Layout
176
+ nav={nav}
177
+ logo={<span className="font-bold text-primary">MyApp</span>}
178
+ header={<Button variant="ghost" size="sm">Logout</Button>}
179
+ >
180
+ {/* page content here */}
181
+ </Layout>
182
+ )
183
+ }`,
184
+ },
185
+ // ─── OVERLAY ──────────────────────────────────────────────────────────────
186
+ {
187
+ name: 'Modal',
188
+ importName: 'Modal, ModalTrigger',
189
+ category: 'overlay',
190
+ description: 'Accessible modal dialog with focus trap, backdrop, and animation. Uses React Aria DialogTrigger.',
191
+ useCases: ['confirmation dialog', 'create/edit modal', 'detail view modal'],
192
+ props: [
193
+ { name: 'title', type: 'string', required: false, description: 'Modal header title' },
194
+ { name: 'size', type: "'sm' | 'md' | 'lg' | 'xl' | 'full'", required: false, default: "'md'", description: 'Modal width' },
195
+ { name: 'footer', type: 'ReactNode', required: false, description: 'Modal footer content' },
196
+ { name: 'children', type: 'ReactNode', required: true, description: 'Modal body content' },
197
+ ],
198
+ example: `import { Modal, ModalTrigger, Button } from '@dangbt/pro-ui'
199
+ import { DialogTrigger } from 'react-aria-components'
200
+
201
+ export function DeleteConfirm() {
202
+ return (
203
+ <DialogTrigger>
204
+ <Button variant="danger">Delete</Button>
205
+ <Modal
206
+ title="Confirm Delete"
207
+ footer={
208
+ <div className="flex gap-2 justify-end">
209
+ <Button variant="ghost" slot="close">Cancel</Button>
210
+ <Button variant="solid" onPress={() => handleDelete()}>Delete</Button>
211
+ </div>
212
+ }
213
+ >
214
+ Are you sure you want to delete this item? This action cannot be undone.
215
+ </Modal>
216
+ </DialogTrigger>
217
+ )
218
+ }`,
219
+ },
220
+ {
221
+ name: 'Drawer',
222
+ importName: 'Drawer',
223
+ category: 'overlay',
224
+ description: 'Slide-in panel from left, right, or bottom. Ideal for filter panels, mobile nav, detail views.',
225
+ useCases: ['filter panel', 'mobile navigation', 'detail side panel', 'slide-in form'],
226
+ props: [
227
+ { name: 'placement', type: "'left' | 'right' | 'bottom'", required: false, default: "'right'", description: 'Which edge to slide from' },
228
+ { name: 'size', type: "'sm' | 'md' | 'lg'", required: false, default: "'md'", description: 'Drawer width/height' },
229
+ { name: 'title', type: 'string', required: false, description: 'Drawer header title' },
230
+ { name: 'withOverlay', type: 'boolean', required: false, default: 'true', description: 'Show backdrop overlay' },
231
+ { name: 'children', type: 'ReactNode', required: true, description: 'Drawer body content' },
232
+ ],
233
+ example: `import { Drawer, Button } from '@dangbt/pro-ui'
234
+ import { DialogTrigger } from 'react-aria-components'
235
+
236
+ export function FilterDrawer() {
237
+ return (
238
+ <DialogTrigger>
239
+ <Button variant="outline">Filters</Button>
240
+ <Drawer title="Filter Options" placement="right">
241
+ {/* filter form content */}
242
+ </Drawer>
243
+ </DialogTrigger>
244
+ )
245
+ }`,
246
+ },
247
+ {
248
+ name: 'Popover',
249
+ importName: 'Popover',
250
+ category: 'overlay',
251
+ description: 'Floating popover panel anchored to a trigger element. Good for contextual menus and info panels.',
252
+ useCases: ['context menu', 'info popover', 'floating panel'],
253
+ props: [
254
+ { name: 'children', type: 'ReactNode', required: true, description: 'Popover content' },
255
+ { name: 'placement', type: 'Placement', required: false, default: "'bottom'", description: 'Placement relative to trigger' },
256
+ { name: 'showArrow', type: 'boolean', required: false, default: 'true', description: 'Show arrow pointing to trigger' },
257
+ ],
258
+ example: `import { Popover, Button } from '@dangbt/pro-ui'
259
+ import { DialogTrigger } from 'react-aria-components'
260
+
261
+ export function InfoPopover() {
262
+ return (
263
+ <DialogTrigger>
264
+ <Button variant="ghost" size="sm">ⓘ Info</Button>
265
+ <Popover>
266
+ <p className="text-sm">This is additional context information.</p>
267
+ </Popover>
268
+ </DialogTrigger>
269
+ )
270
+ }`,
271
+ },
272
+ {
273
+ name: 'Toast',
274
+ importName: 'ToastProvider, toast',
275
+ category: 'feedback',
276
+ description: 'Global toast notifications. Mount ToastProvider once at app root, call toast() anywhere.',
277
+ useCases: ['success notification', 'error message', 'action confirmation', 'system alert'],
278
+ props: [
279
+ { name: 'position', type: "'top-right' | 'top-center' | 'bottom-right' | 'bottom-center'", required: false, default: "'top-right'", description: 'Toast position on screen' },
280
+ ],
281
+ example: `// 1. Mount provider once (e.g. in App.tsx)
282
+ import { ToastProvider, toast } from '@dangbt/pro-ui'
283
+
284
+ export function App() {
285
+ return (
286
+ <>
287
+ <ToastProvider />
288
+ {/* rest of app */}
289
+ </>
290
+ )
291
+ }
292
+
293
+ // 2. Call from anywhere
294
+ toast.success('User created successfully!')
295
+ toast.error('Something went wrong.')
296
+ toast.warning('Please review your input.')
297
+ toast.info('New version available.')
298
+
299
+ // With options:
300
+ toast.success('Saved!', { duration: 5000, persistent: false })`,
301
+ },
302
+ // ─── THEME ────────────────────────────────────────────────────────────────
303
+ {
304
+ name: 'ThemeProvider',
305
+ importName: 'ThemeProvider, useTheme',
306
+ category: 'theme',
307
+ description: 'Context provider for light/dark/system theme. Persists to localStorage, listens to system preference. Toggle class .dark on <html> element.',
308
+ useCases: ['dark mode', 'light/dark toggle', 'theme switching', 'system theme'],
309
+ props: [
310
+ { name: 'defaultTheme', type: "'light' | 'dark' | 'system'", required: false, default: "'system'", description: 'Initial theme if nothing in localStorage' },
311
+ { name: 'storageKey', type: 'string', required: false, default: "'pro-ui-theme'", description: 'localStorage key for persistence' },
312
+ { name: 'children', type: 'ReactNode', required: true, description: 'App content' },
313
+ ],
314
+ example: `// 1. Wrap app (e.g. main.tsx)
315
+ import { ThemeProvider } from '@dangbt/pro-ui'
316
+
317
+ ReactDOM.createRoot(document.getElementById('root')!).render(
318
+ <ThemeProvider defaultTheme="system">
319
+ <App />
320
+ </ThemeProvider>
321
+ )
322
+
323
+ // 2. Use in any component
324
+ import { useTheme } from '@dangbt/pro-ui'
325
+
326
+ export function ThemeToggle() {
327
+ const { theme, setTheme } = useTheme()
328
+ return (
329
+ <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
330
+ {theme === 'dark' ? '☀️ Light' : '🌙 Dark'}
331
+ </button>
332
+ )
333
+ }`,
334
+ },
335
+ // ─── DISPLAY ──────────────────────────────────────────────────────────────
336
+ {
337
+ name: 'Statistic',
338
+ importName: 'Statistic',
339
+ category: 'display',
340
+ description: 'KPI card showing a metric value with optional trend indicator (up/down/neutral), prefix, suffix, and formatter.',
341
+ useCases: ['KPI card', 'metric display', 'dashboard stat', 'trend indicator'],
342
+ props: [
343
+ { name: 'title', type: 'string', required: true, description: 'Metric label' },
344
+ { name: 'value', type: 'number | string', required: true, description: 'The metric value' },
345
+ { name: 'prefix', type: 'ReactNode', required: false, description: 'Content before value (e.g. icon or currency symbol)' },
346
+ { name: 'suffix', type: 'ReactNode', required: false, description: 'Content after value (e.g. unit)' },
347
+ { name: 'trend', type: "'up' | 'down' | 'neutral'", required: false, description: 'Trend direction indicator' },
348
+ { name: 'trendValue', type: 'string', required: false, description: 'Trend percentage or delta text (e.g. "+12%")' },
349
+ { name: 'formatter', type: '(value: number | string) => ReactNode', required: false, description: 'Custom value formatter' },
350
+ { name: 'size', type: "'sm' | 'md' | 'lg'", required: false, default: "'md'", description: 'Display size' },
351
+ ],
352
+ example: `import { Statistic } from '@dangbt/pro-ui'
353
+ import { DollarSign } from 'lucide-react'
354
+
355
+ export function DashboardStats() {
356
+ return (
357
+ <div className="grid grid-cols-3 gap-4">
358
+ <Statistic
359
+ title="Total Revenue"
360
+ value={125430}
361
+ prefix={<DollarSign size={16} />}
362
+ trend="up"
363
+ trendValue="+12.5%"
364
+ formatter={(v) => Number(v).toLocaleString()}
365
+ />
366
+ <Statistic title="Active Users" value={2847} trend="up" trendValue="+8%" />
367
+ <Statistic title="Churn Rate" value="3.2%" trend="down" trendValue="-0.5%" />
368
+ </div>
369
+ )
370
+ }`,
371
+ },
372
+ {
373
+ name: 'Steps',
374
+ importName: 'Steps',
375
+ category: 'display',
376
+ description: 'Multi-step progress indicator. Supports horizontal/vertical orientation, error state, clickable steps, and custom icons.',
377
+ useCases: ['multi-step form', 'onboarding flow', 'progress indicator', 'wizard UI'],
378
+ props: [
379
+ { name: 'items', type: 'StepItem[]', required: true, description: 'Array of step definitions ({ title, description?, status?, icon? })' },
380
+ { name: 'current', type: 'number', required: true, description: 'Zero-based index of the current step' },
381
+ { name: 'direction', type: "'horizontal' | 'vertical'", required: false, default: "'horizontal'", description: 'Layout direction' },
382
+ { name: 'onChange', type: '(index: number) => void', required: false, description: 'Called when a step is clicked (makes steps clickable)' },
383
+ ],
384
+ example: `import { Steps } from '@dangbt/pro-ui'
385
+ import { useState } from 'react'
386
+
387
+ export function OnboardingWizard() {
388
+ const [step, setStep] = useState(0)
389
+
390
+ return (
391
+ <Steps
392
+ current={step}
393
+ onChange={setStep}
394
+ items={[
395
+ { title: 'Account', description: 'Create your account' },
396
+ { title: 'Profile', description: 'Set up your profile' },
397
+ { title: 'Done', description: 'All set!' },
398
+ ]}
399
+ />
400
+ )
401
+ }`,
402
+ },
403
+ {
404
+ name: 'Empty',
405
+ importName: 'Empty',
406
+ category: 'display',
407
+ description: 'Empty state placeholder with optional custom image, title, description, and action button.',
408
+ useCases: ['empty state', 'no data placeholder', 'zero state UI'],
409
+ props: [
410
+ { name: 'title', type: 'string', required: false, default: "'No data'", description: 'Empty state headline' },
411
+ { name: 'description', type: 'string', required: false, description: 'Supporting text' },
412
+ { name: 'image', type: 'ReactNode', required: false, description: 'Custom illustration or icon' },
413
+ { name: 'action', type: 'ReactNode', required: false, description: 'CTA button or link' },
414
+ ],
415
+ example: `import { Empty, Button } from '@dangbt/pro-ui'
416
+
417
+ export function EmptyUsers() {
418
+ return (
419
+ <Empty
420
+ title="No users yet"
421
+ description="Add your first user to get started."
422
+ action={<Button variant="solid" onPress={() => {}}>Add User</Button>}
423
+ />
424
+ )
425
+ }`,
426
+ },
427
+ // ─── FOUNDATION ───────────────────────────────────────────────────────────
428
+ {
429
+ name: 'Button',
430
+ importName: 'Button',
431
+ category: 'form',
432
+ description: 'Accessible button with variants (solid, outline, ghost, danger), sizes, loading state, and icon support. Built on React Aria.',
433
+ useCases: ['primary action', 'secondary action', 'danger action', 'icon button', 'loading button'],
434
+ props: [
435
+ { name: 'variant', type: "'solid' | 'outline' | 'ghost' | 'danger'", required: false, default: "'outline'", description: 'Visual style' },
436
+ { name: 'size', type: "'sm' | 'md' | 'lg'", required: false, default: "'md'", description: 'Button size' },
437
+ { name: 'loading', type: 'boolean', required: false, description: 'Show spinner and disable interaction' },
438
+ { name: 'isDisabled', type: 'boolean', required: false, description: 'Disable the button' },
439
+ { name: 'onPress', type: '() => void', required: false, description: 'Press handler (use onPress, not onClick)' },
440
+ { name: 'type', type: "'button' | 'submit' | 'reset'", required: false, default: "'button'", description: 'HTML button type' },
441
+ ],
442
+ example: `import { Button } from '@dangbt/pro-ui'
443
+ import { Plus, Trash2 } from 'lucide-react'
444
+
445
+ // Variants
446
+ <Button variant="solid" onPress={handleSave}>Save</Button>
447
+ <Button variant="outline" onPress={handleCancel}>Cancel</Button>
448
+ <Button variant="ghost" onPress={handleEdit}>Edit</Button>
449
+ <Button variant="danger" onPress={handleDelete}>Delete</Button>
450
+
451
+ // With icon
452
+ <Button variant="solid" onPress={handleAdd}>
453
+ <Plus size={16} /> Add Item
454
+ </Button>
455
+
456
+ // Loading state
457
+ <Button variant="solid" loading={isSubmitting} type="submit">
458
+ Submit
459
+ </Button>`,
460
+ },
461
+ {
462
+ name: 'Input',
463
+ importName: 'Input',
464
+ category: 'form',
465
+ description: 'Text input field with label, description, error message, prefix/suffix icons. Built on React Aria.',
466
+ useCases: ['text input', 'search field', 'email input', 'password field'],
467
+ props: [
468
+ { name: 'label', type: 'string', required: false, description: 'Input label' },
469
+ { name: 'type', type: 'string', required: false, default: "'text'", description: 'HTML input type (text, email, password, etc.)' },
470
+ { name: 'placeholder', type: 'string', required: false, description: 'Placeholder text' },
471
+ { name: 'description', type: 'string', required: false, description: 'Helper text below input' },
472
+ { name: 'errorMessage', type: 'string', required: false, description: 'Error text (also sets invalid state)' },
473
+ { name: 'prefix', type: 'ReactNode', required: false, description: 'Icon or text before input' },
474
+ { name: 'suffix', type: 'ReactNode', required: false, description: 'Icon or text after input' },
475
+ { name: 'isDisabled', type: 'boolean', required: false, description: 'Disable the input' },
476
+ { name: 'size', type: "'sm' | 'md' | 'lg'", required: false, default: "'md'", description: 'Input size' },
477
+ ],
478
+ example: `import { Input } from '@dangbt/pro-ui'
479
+ import { Search, Mail } from 'lucide-react'
480
+
481
+ <Input label="Email" type="email" placeholder="you@example.com" prefix={<Mail size={14} />} />
482
+ <Input label="Search" placeholder="Search..." prefix={<Search size={14} />} />
483
+ <Input label="Name" errorMessage="Name is required" />`,
484
+ },
485
+ {
486
+ name: 'Select',
487
+ importName: 'Select',
488
+ category: 'form',
489
+ description: 'Accessible dropdown select with keyboard navigation, search, and custom option rendering.',
490
+ useCases: ['dropdown selection', 'enum picker', 'status selector'],
491
+ props: [
492
+ { name: 'label', type: 'string', required: false, description: 'Select label' },
493
+ { name: 'placeholder', type: 'string', required: false, description: 'Placeholder when no value selected' },
494
+ { name: 'options', type: '{ value: string; label: string }[]', required: true, description: 'Options list' },
495
+ { name: 'errorMessage', type: 'string', required: false, description: 'Error state text' },
496
+ { name: 'isDisabled', type: 'boolean', required: false, description: 'Disable the select' },
497
+ ],
498
+ example: `import { Select } from '@dangbt/pro-ui'
499
+
500
+ <Select
501
+ label="Role"
502
+ placeholder="Select a role"
503
+ options={[
504
+ { value: 'admin', label: 'Administrator' },
505
+ { value: 'user', label: 'User' },
506
+ { value: 'viewer', label: 'Viewer' },
507
+ ]}
508
+ />`,
509
+ },
510
+ {
511
+ name: 'Badge',
512
+ importName: 'Badge',
513
+ category: 'display',
514
+ description: 'Small status label with color variants for indicating states.',
515
+ useCases: ['status badge', 'tag', 'label chip', 'count indicator'],
516
+ props: [
517
+ { name: 'variant', type: "'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info'", required: false, default: "'default'", description: 'Color variant' },
518
+ { name: 'children', type: 'ReactNode', required: true, description: 'Badge content' },
519
+ ],
520
+ example: `import { Badge } from '@dangbt/pro-ui'
521
+
522
+ <Badge variant="success">Active</Badge>
523
+ <Badge variant="danger">Inactive</Badge>
524
+ <Badge variant="warning">Pending</Badge>
525
+ <Badge variant="info">Draft</Badge>`,
526
+ },
527
+ {
528
+ name: 'Card',
529
+ importName: 'Card',
530
+ category: 'display',
531
+ description: 'Container card with optional header, footer, padding, and shadow.',
532
+ useCases: ['content card', 'info panel', 'dashboard widget', 'settings section'],
533
+ props: [
534
+ { name: 'header', type: 'ReactNode', required: false, description: 'Card header content' },
535
+ { name: 'footer', type: 'ReactNode', required: false, description: 'Card footer content' },
536
+ { name: 'noPadding', type: 'boolean', required: false, description: 'Remove default padding' },
537
+ { name: 'children', type: 'ReactNode', required: true, description: 'Card body content' },
538
+ ],
539
+ example: `import { Card } from '@dangbt/pro-ui'
540
+
541
+ <Card header={<h3 className="font-semibold">Account Settings</h3>}>
542
+ <p>Manage your account preferences here.</p>
543
+ </Card>`,
544
+ },
545
+ {
546
+ name: 'Menu',
547
+ importName: 'Menu, MenuItem, MenuSection',
548
+ category: 'overlay',
549
+ description: 'Dropdown action menu with keyboard navigation, sections, and icons.',
550
+ useCases: ['action menu', 'context menu', 'dropdown options', 'more options button'],
551
+ props: [
552
+ { name: 'items', type: 'MenuItemDef[]', required: true, description: 'Menu item definitions' },
553
+ { name: 'placement', type: 'Placement', required: false, description: 'Menu placement relative to trigger' },
554
+ ],
555
+ example: `import { Menu, Button } from '@dangbt/pro-ui'
556
+ import { DialogTrigger } from 'react-aria-components'
557
+ import { MoreHorizontal } from 'lucide-react'
558
+
559
+ <DialogTrigger>
560
+ <Button variant="ghost" size="sm"><MoreHorizontal size={16} /></Button>
561
+ <Menu
562
+ items={[
563
+ { key: 'edit', label: 'Edit', onAction: () => handleEdit() },
564
+ { key: 'duplicate', label: 'Duplicate', onAction: () => handleDuplicate() },
565
+ { key: 'delete', label: 'Delete', danger: true, onAction: () => handleDelete() },
566
+ ]}
567
+ />
568
+ </DialogTrigger>`,
569
+ },
570
+ {
571
+ name: 'Tabs',
572
+ importName: 'Tabs, TabList, Tab, TabPanel',
573
+ category: 'display',
574
+ description: 'Accessible tab navigation with keyboard support.',
575
+ useCases: ['tab navigation', 'content switcher', 'section tabs'],
576
+ props: [
577
+ { name: 'defaultSelectedKey', type: 'string', required: false, description: 'Default selected tab key' },
578
+ { name: 'onSelectionChange', type: '(key: Key) => void', required: false, description: 'Called on tab change' },
579
+ ],
580
+ example: `import { Tabs, TabList, Tab, TabPanel } from '@dangbt/pro-ui'
581
+
582
+ <Tabs defaultSelectedKey="overview">
583
+ <TabList>
584
+ <Tab id="overview">Overview</Tab>
585
+ <Tab id="activity">Activity</Tab>
586
+ <Tab id="settings">Settings</Tab>
587
+ </TabList>
588
+ <TabPanel id="overview">Overview content</TabPanel>
589
+ <TabPanel id="activity">Activity content</TabPanel>
590
+ <TabPanel id="settings">Settings content</TabPanel>
591
+ </Tabs>`,
592
+ },
593
+ {
594
+ name: 'Alert',
595
+ importName: 'Alert',
596
+ category: 'feedback',
597
+ description: 'Inline alert message with icon and color variants for info, success, warning, and error states.',
598
+ useCases: ['inline alert', 'warning message', 'error banner', 'info notice'],
599
+ props: [
600
+ { name: 'variant', type: "'info' | 'success' | 'warning' | 'danger'", required: false, default: "'info'", description: 'Alert severity' },
601
+ { name: 'title', type: 'string', required: false, description: 'Alert headline' },
602
+ { name: 'children', type: 'ReactNode', required: true, description: 'Alert body text' },
603
+ { name: 'onDismiss', type: '() => void', required: false, description: 'If provided, shows a dismiss button' },
604
+ ],
605
+ example: `import { Alert } from '@dangbt/pro-ui'
606
+
607
+ <Alert variant="warning" title="Heads up">
608
+ Your trial expires in 3 days. Upgrade to keep access.
609
+ </Alert>
610
+ <Alert variant="danger" onDismiss={() => setError(null)}>
611
+ Failed to save changes. Please try again.
612
+ </Alert>`,
613
+ },
614
+ {
615
+ name: 'Avatar',
616
+ importName: 'Avatar, AvatarGroup',
617
+ category: 'display',
618
+ description: 'User avatar with image, initials fallback, and size variants. AvatarGroup stacks multiple avatars.',
619
+ useCases: ['user avatar', 'profile picture', 'team members display'],
620
+ props: [
621
+ { name: 'src', type: 'string', required: false, description: 'Image URL' },
622
+ { name: 'name', type: 'string', required: false, description: 'Name for initials fallback and aria-label' },
623
+ { name: 'size', type: "'sm' | 'md' | 'lg' | 'xl'", required: false, default: "'md'", description: 'Avatar size' },
624
+ ],
625
+ example: `import { Avatar, AvatarGroup } from '@dangbt/pro-ui'
626
+
627
+ <Avatar src="/avatar.jpg" name="John Doe" size="md" />
628
+ <Avatar name="Jane Smith" size="lg" /> {/* initials fallback */}
629
+
630
+ <AvatarGroup max={3}>
631
+ <Avatar name="Alice" />
632
+ <Avatar name="Bob" />
633
+ <Avatar name="Charlie" />
634
+ <Avatar name="Diana" />
635
+ </AvatarGroup>`,
636
+ },
637
+ {
638
+ name: 'Tooltip',
639
+ importName: 'Tooltip',
640
+ category: 'overlay',
641
+ description: 'Accessible tooltip on hover/focus with customizable placement.',
642
+ useCases: ['hover tooltip', 'icon label', 'help text on hover'],
643
+ props: [
644
+ { name: 'content', type: 'string | ReactNode', required: true, description: 'Tooltip text or content' },
645
+ { name: 'placement', type: 'Placement', required: false, default: "'top'", description: 'Tooltip placement' },
646
+ { name: 'children', type: 'ReactNode', required: true, description: 'The element that triggers the tooltip' },
647
+ ],
648
+ example: `import { Tooltip, Button } from '@dangbt/pro-ui'
649
+ import { Info } from 'lucide-react'
650
+
651
+ <Tooltip content="This field is required for compliance">
652
+ <Button variant="ghost" size="sm"><Info size={14} /></Button>
653
+ </Tooltip>`,
654
+ },
655
+ {
656
+ name: 'Spinner',
657
+ importName: 'Spinner',
658
+ category: 'feedback',
659
+ description: 'Loading spinner with size and color variants.',
660
+ useCases: ['loading indicator', 'async operation feedback'],
661
+ props: [
662
+ { name: 'size', type: "'sm' | 'md' | 'lg'", required: false, default: "'md'", description: 'Spinner size' },
663
+ ],
664
+ example: `import { Spinner } from '@dangbt/pro-ui'
665
+
666
+ {isLoading && <Spinner size="sm" />}`,
667
+ },
668
+ {
669
+ name: 'Skeleton',
670
+ importName: 'Skeleton',
671
+ category: 'feedback',
672
+ description: 'Content placeholder skeleton for loading states.',
673
+ useCases: ['loading skeleton', 'content placeholder', 'shimmer loading'],
674
+ props: [
675
+ { name: 'className', type: 'string', required: false, description: 'Custom classes for size/shape (e.g. w-full h-4 rounded)' },
676
+ { name: 'count', type: 'number', required: false, default: '1', description: 'Number of skeleton lines to render' },
677
+ ],
678
+ example: `import { Skeleton } from '@dangbt/pro-ui'
679
+
680
+ {isLoading ? (
681
+ <div className="space-y-2">
682
+ <Skeleton className="h-4 w-3/4 rounded" />
683
+ <Skeleton className="h-4 w-full rounded" />
684
+ <Skeleton className="h-4 w-1/2 rounded" />
685
+ </div>
686
+ ) : <ActualContent />}`,
687
+ },
688
+ ];
689
+ export const CATEGORIES = {
690
+ data: 'Data Display & Tables',
691
+ form: 'Forms & Inputs',
692
+ layout: 'Layout',
693
+ overlay: 'Overlays & Modals',
694
+ feedback: 'Feedback & Status',
695
+ display: 'Display & Typography',
696
+ theme: 'Theming',
697
+ };
698
+ //# sourceMappingURL=components-data.js.map