@moontra/moonui 2.0.7 → 2.0.9

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.
Files changed (94) hide show
  1. package/package.json +26 -19
  2. package/src/__tests__/use-intersection-observer.test.tsx +216 -0
  3. package/src/__tests__/use-local-storage.test.tsx +174 -0
  4. package/src/__tests__/use-pro-access.test.tsx +183 -0
  5. package/src/components/ui/__tests__/accordion.test.tsx +571 -0
  6. package/src/components/ui/__tests__/alert.test.tsx +484 -0
  7. package/src/components/ui/__tests__/aspect-ratio.test.tsx +492 -0
  8. package/src/components/ui/__tests__/avatar.test.tsx +382 -0
  9. package/src/components/ui/__tests__/badge.test.tsx +364 -0
  10. package/src/components/ui/__tests__/breadcrumb.test.tsx +687 -0
  11. package/src/components/ui/__tests__/button.test.tsx +91 -0
  12. package/src/components/ui/__tests__/card.test.tsx +104 -0
  13. package/src/components/ui/__tests__/checkbox.test.tsx +591 -0
  14. package/src/components/ui/__tests__/collapsible.test.tsx +592 -0
  15. package/src/components/ui/__tests__/color-picker.test.tsx +365 -0
  16. package/src/components/ui/__tests__/command.test.tsx +677 -0
  17. package/src/components/ui/__tests__/data-table.test.tsx +256 -0
  18. package/src/components/ui/__tests__/date-picker.test.tsx +320 -0
  19. package/src/components/ui/__tests__/dialog.test.tsx +764 -0
  20. package/src/components/ui/__tests__/input.test.tsx +318 -0
  21. package/src/components/ui/__tests__/label.test.tsx +103 -0
  22. package/src/components/ui/__tests__/popover.test.tsx +637 -0
  23. package/src/components/ui/__tests__/progress.test.tsx +382 -0
  24. package/src/components/ui/__tests__/radio-group.test.tsx +555 -0
  25. package/src/components/ui/__tests__/select.test.tsx +705 -0
  26. package/src/components/ui/__tests__/skeleton.test.tsx +253 -0
  27. package/src/components/ui/__tests__/slider.test.tsx +493 -0
  28. package/src/components/ui/__tests__/switch.test.tsx +372 -0
  29. package/src/components/ui/__tests__/table.test.tsx +824 -0
  30. package/src/components/ui/__tests__/tabs.test.tsx +887 -0
  31. package/src/components/ui/__tests__/toast.test.tsx +458 -0
  32. package/src/components/ui/__tests__/tooltip.test.tsx +583 -0
  33. package/src/components/ui/accordion.tsx +63 -0
  34. package/src/components/ui/alert.tsx +130 -0
  35. package/src/components/ui/aspect-ratio.tsx +72 -0
  36. package/src/components/ui/avatar.tsx +135 -0
  37. package/src/components/ui/badge.tsx +225 -0
  38. package/src/components/ui/breadcrumb.tsx +207 -0
  39. package/src/components/ui/button.stories.tsx +162 -0
  40. package/src/components/ui/button.tsx +221 -0
  41. package/src/components/ui/calendar.tsx +262 -0
  42. package/src/components/ui/card.stories.tsx +208 -0
  43. package/src/components/ui/card.tsx +141 -0
  44. package/src/components/ui/checkbox.tsx +256 -0
  45. package/src/components/ui/collapsible.tsx +129 -0
  46. package/src/components/ui/color-picker.tsx +664 -0
  47. package/src/components/ui/command.tsx +218 -0
  48. package/src/components/ui/data-table.stories.tsx +509 -0
  49. package/src/components/ui/data-table.tsx +623 -0
  50. package/src/components/ui/date-picker.stories.tsx +321 -0
  51. package/src/components/ui/date-picker.tsx +603 -0
  52. package/src/components/ui/dialog.tsx +332 -0
  53. package/src/components/ui/dropdown-menu.tsx +200 -0
  54. package/src/components/ui/file-upload.tsx +400 -0
  55. package/src/components/ui/github-stars.tsx +201 -0
  56. package/src/components/ui/index.ts +12 -0
  57. package/src/components/ui/input.stories.tsx +255 -0
  58. package/src/components/ui/input.tsx +219 -0
  59. package/src/components/ui/label.tsx +26 -0
  60. package/src/components/ui/locked-component.tsx +215 -0
  61. package/src/components/ui/moon-logo.tsx +97 -0
  62. package/src/components/ui/pagination.tsx +116 -0
  63. package/src/components/ui/popover.tsx +183 -0
  64. package/src/components/ui/progress.tsx +182 -0
  65. package/src/components/ui/radio-group.tsx +243 -0
  66. package/src/components/ui/select.tsx +273 -0
  67. package/src/components/ui/separator.tsx +140 -0
  68. package/src/components/ui/simple-editor.tsx +652 -0
  69. package/src/components/ui/skeleton.tsx +351 -0
  70. package/src/components/ui/slider.tsx +351 -0
  71. package/src/components/ui/switch.tsx +83 -0
  72. package/src/components/ui/table.tsx +322 -0
  73. package/src/components/ui/tabs.tsx +195 -0
  74. package/src/components/ui/textarea.tsx +46 -0
  75. package/src/components/ui/toast.tsx +313 -0
  76. package/src/components/ui/toggle.tsx +47 -0
  77. package/src/components/ui/tooltip.tsx +152 -0
  78. package/src/docs/theme-system.md +1194 -0
  79. package/src/index.tsx +39 -0
  80. package/src/lib/micro-interactions.ts +255 -0
  81. package/src/lib/theme.tsx +398 -0
  82. package/src/lib/utils.ts +69 -0
  83. package/src/styles/design-system.css +365 -0
  84. package/src/styles/index.css +4 -0
  85. package/src/styles/tailwind.css +6 -0
  86. package/src/styles/tokens.css +453 -0
  87. package/src/use-intersection-observer.tsx +154 -0
  88. package/src/use-local-storage.tsx +71 -0
  89. package/src/use-paddle.ts +138 -0
  90. package/src/use-performance-optimizer.ts +379 -0
  91. package/src/use-pro-access.ts +141 -0
  92. package/src/use-scroll-animation.ts +221 -0
  93. package/src/use-subscription.ts +37 -0
  94. package/src/use-toast.ts +32 -0
@@ -0,0 +1,218 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Search } from "lucide-react"
5
+ import { Command as CommandPrimitive } from "cmdk"
6
+ import { cva, type VariantProps } from "class-variance-authority"
7
+
8
+ import { cn } from "../../lib/utils"
9
+ import { Dialog, DialogContent, DialogTitle } from "./dialog"
10
+
11
+ /**
12
+ * Command (Komut Paleti) Bileşeni
13
+ *
14
+ * Gerçek command palette işlevselliği ile klavye navigasyonu, arama ve filtreleme.
15
+ * cmdk kütüphanesi üzerine inşa edilmiş, tam özellikli command interface.
16
+ */
17
+
18
+ const commandVariants = cva(
19
+ "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
20
+ {
21
+ variants: {
22
+ variant: {
23
+ default: "bg-popover text-popover-foreground",
24
+ glass: "bg-background/80 text-foreground backdrop-blur-sm",
25
+ bordered: "bg-popover text-popover-foreground border border-border",
26
+ },
27
+ size: {
28
+ sm: "min-h-[200px]",
29
+ default: "min-h-[300px]",
30
+ lg: "min-h-[400px]",
31
+ },
32
+ },
33
+ defaultVariants: {
34
+ variant: "default",
35
+ size: "default",
36
+ },
37
+ }
38
+ )
39
+
40
+ // Command bileşeni - cmdk primitive wrapper
41
+ interface CommandProps
42
+ extends React.ComponentProps<typeof CommandPrimitive>,
43
+ VariantProps<typeof commandVariants> {}
44
+
45
+ const Command = React.forwardRef<
46
+ React.ElementRef<typeof CommandPrimitive>,
47
+ CommandProps
48
+ >(({ className, variant, size, ...props }, ref) => (
49
+ <CommandPrimitive
50
+ ref={ref}
51
+ className={cn(commandVariants({ variant, size }), className)}
52
+ {...props}
53
+ />
54
+ ))
55
+ Command.displayName = CommandPrimitive.displayName
56
+
57
+ // CommandDialog bileşeni
58
+ interface CommandDialogProps extends React.ComponentProps<typeof Dialog> {
59
+ commandClassName?: string
60
+ children?: React.ReactNode
61
+ }
62
+
63
+ const CommandDialog = ({
64
+ children,
65
+ commandClassName,
66
+ ...props
67
+ }: CommandDialogProps) => {
68
+ return (
69
+ <Dialog {...props}>
70
+ <DialogContent className="overflow-hidden p-0 shadow-lg" hideCloseButton>
71
+ <DialogTitle className="sr-only">Command Menu</DialogTitle>
72
+ <Command className={cn(
73
+ "[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5",
74
+ commandClassName
75
+ )}>
76
+ {children}
77
+ </Command>
78
+ </DialogContent>
79
+ </Dialog>
80
+ )
81
+ }
82
+
83
+ // CommandInput bileşeni
84
+ interface CommandInputProps
85
+ extends React.ComponentProps<typeof CommandPrimitive.Input> {}
86
+
87
+ const CommandInput = React.forwardRef<
88
+ React.ElementRef<typeof CommandPrimitive.Input>,
89
+ CommandInputProps
90
+ >(({ className, ...props }, ref) => (
91
+ <div className="flex items-center border-b px-3" cmdk-input-wrapper="">
92
+ <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
93
+ <CommandPrimitive.Input
94
+ ref={ref}
95
+ className={cn(
96
+ "flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
97
+ className
98
+ )}
99
+ {...props}
100
+ />
101
+ </div>
102
+ ))
103
+ CommandInput.displayName = CommandPrimitive.Input.displayName
104
+
105
+ // CommandList bileşeni
106
+ interface CommandListProps
107
+ extends React.ComponentProps<typeof CommandPrimitive.List> {}
108
+
109
+ const CommandList = React.forwardRef<
110
+ React.ElementRef<typeof CommandPrimitive.List>,
111
+ CommandListProps
112
+ >(({ className, ...props }, ref) => (
113
+ <CommandPrimitive.List
114
+ ref={ref}
115
+ className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
116
+ {...props}
117
+ />
118
+ ))
119
+ CommandList.displayName = CommandPrimitive.List.displayName
120
+
121
+ // CommandEmpty bileşeni
122
+ interface CommandEmptyProps
123
+ extends React.ComponentProps<typeof CommandPrimitive.Empty> {}
124
+
125
+ const CommandEmpty = React.forwardRef<
126
+ React.ElementRef<typeof CommandPrimitive.Empty>,
127
+ CommandEmptyProps
128
+ >(({ className, ...props }, ref) => (
129
+ <CommandPrimitive.Empty
130
+ ref={ref}
131
+ className={cn("py-6 text-center text-sm text-muted-foreground", className)}
132
+ {...props}
133
+ />
134
+ ))
135
+ CommandEmpty.displayName = CommandPrimitive.Empty.displayName
136
+
137
+ // CommandGroup bileşeni
138
+ interface CommandGroupProps
139
+ extends React.ComponentProps<typeof CommandPrimitive.Group> {}
140
+
141
+ const CommandGroup = React.forwardRef<
142
+ React.ElementRef<typeof CommandPrimitive.Group>,
143
+ CommandGroupProps
144
+ >(({ className, ...props }, ref) => (
145
+ <CommandPrimitive.Group
146
+ ref={ref}
147
+ className={cn(
148
+ "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
149
+ className
150
+ )}
151
+ {...props}
152
+ />
153
+ ))
154
+ CommandGroup.displayName = CommandPrimitive.Group.displayName
155
+
156
+ // CommandSeparator bileşeni
157
+ interface CommandSeparatorProps
158
+ extends React.ComponentProps<typeof CommandPrimitive.Separator> {}
159
+
160
+ const CommandSeparator = React.forwardRef<
161
+ React.ElementRef<typeof CommandPrimitive.Separator>,
162
+ CommandSeparatorProps
163
+ >(({ className, ...props }, ref) => (
164
+ <CommandPrimitive.Separator
165
+ ref={ref}
166
+ className={cn("-mx-1 h-px bg-border", className)}
167
+ {...props}
168
+ />
169
+ ))
170
+ CommandSeparator.displayName = CommandPrimitive.Separator.displayName
171
+
172
+ // CommandItem bileşeni
173
+ interface CommandItemProps
174
+ extends React.ComponentProps<typeof CommandPrimitive.Item> {}
175
+
176
+ const CommandItem = React.forwardRef<
177
+ React.ElementRef<typeof CommandPrimitive.Item>,
178
+ CommandItemProps
179
+ >(({ className, ...props }, ref) => (
180
+ <CommandPrimitive.Item
181
+ ref={ref}
182
+ className={cn(
183
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
184
+ className
185
+ )}
186
+ {...props}
187
+ />
188
+ ))
189
+ CommandItem.displayName = CommandPrimitive.Item.displayName
190
+
191
+ // CommandShortcut bileşeni - utility component
192
+ const CommandShortcut = ({
193
+ className,
194
+ ...props
195
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
196
+ return (
197
+ <span
198
+ className={cn(
199
+ "ml-auto text-xs tracking-widest text-muted-foreground",
200
+ className
201
+ )}
202
+ {...props}
203
+ />
204
+ )
205
+ }
206
+ CommandShortcut.displayName = "CommandShortcut"
207
+
208
+ export {
209
+ Command,
210
+ CommandDialog,
211
+ CommandInput,
212
+ CommandList,
213
+ CommandEmpty,
214
+ CommandGroup,
215
+ CommandItem,
216
+ CommandShortcut,
217
+ CommandSeparator,
218
+ }
@@ -0,0 +1,509 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { DataTable } from './data-table';
3
+ import { Badge } from './badge';
4
+ import { Button } from './button';
5
+ import { MoreHorizontal, ArrowUpDown, Edit, Trash2 } from 'lucide-react';
6
+ import { ColumnDef } from '@tanstack/react-table';
7
+
8
+ // Sample data types
9
+ type User = {
10
+ id: string;
11
+ name: string;
12
+ email: string;
13
+ role: 'admin' | 'user' | 'moderator';
14
+ status: 'active' | 'inactive' | 'pending';
15
+ createdAt: string;
16
+ lastLogin: string;
17
+ };
18
+
19
+ type Product = {
20
+ id: string;
21
+ name: string;
22
+ category: string;
23
+ price: number;
24
+ stock: number;
25
+ status: 'available' | 'out_of_stock' | 'discontinued';
26
+ };
27
+
28
+ // Sample data
29
+ const userData: User[] = [
30
+ {
31
+ id: '1',
32
+ name: 'John Doe',
33
+ email: 'john@example.com',
34
+ role: 'admin',
35
+ status: 'active',
36
+ createdAt: '2023-01-15',
37
+ lastLogin: '2024-01-15',
38
+ },
39
+ {
40
+ id: '2',
41
+ name: 'Jane Smith',
42
+ email: 'jane@example.com',
43
+ role: 'user',
44
+ status: 'active',
45
+ createdAt: '2023-02-20',
46
+ lastLogin: '2024-01-14',
47
+ },
48
+ {
49
+ id: '3',
50
+ name: 'Bob Johnson',
51
+ email: 'bob@example.com',
52
+ role: 'moderator',
53
+ status: 'inactive',
54
+ createdAt: '2023-03-10',
55
+ lastLogin: '2024-01-10',
56
+ },
57
+ {
58
+ id: '4',
59
+ name: 'Alice Brown',
60
+ email: 'alice@example.com',
61
+ role: 'user',
62
+ status: 'pending',
63
+ createdAt: '2023-04-05',
64
+ lastLogin: '2024-01-12',
65
+ },
66
+ {
67
+ id: '5',
68
+ name: 'Charlie Wilson',
69
+ email: 'charlie@example.com',
70
+ role: 'user',
71
+ status: 'active',
72
+ createdAt: '2023-05-01',
73
+ lastLogin: '2024-01-11',
74
+ },
75
+ ];
76
+
77
+ const productData: Product[] = [
78
+ {
79
+ id: '1',
80
+ name: 'Wireless Headphones',
81
+ category: 'Electronics',
82
+ price: 299.99,
83
+ stock: 45,
84
+ status: 'available',
85
+ },
86
+ {
87
+ id: '2',
88
+ name: 'Gaming Mouse',
89
+ category: 'Electronics',
90
+ price: 89.99,
91
+ stock: 0,
92
+ status: 'out_of_stock',
93
+ },
94
+ {
95
+ id: '3',
96
+ name: 'Mechanical Keyboard',
97
+ category: 'Electronics',
98
+ price: 159.99,
99
+ stock: 23,
100
+ status: 'available',
101
+ },
102
+ {
103
+ id: '4',
104
+ name: 'USB-C Cable',
105
+ category: 'Accessories',
106
+ price: 19.99,
107
+ stock: 100,
108
+ status: 'available',
109
+ },
110
+ {
111
+ id: '5',
112
+ name: 'Laptop Stand',
113
+ category: 'Accessories',
114
+ price: 49.99,
115
+ stock: 0,
116
+ status: 'discontinued',
117
+ },
118
+ ];
119
+
120
+ // User columns
121
+ const userColumns: ColumnDef<User>[] = [
122
+ {
123
+ accessorKey: 'name',
124
+ header: ({ column }) => (
125
+ <Button
126
+ variant="ghost"
127
+ onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
128
+ >
129
+ Name
130
+ <ArrowUpDown className="ml-2 h-4 w-4" />
131
+ </Button>
132
+ ),
133
+ },
134
+ {
135
+ accessorKey: 'email',
136
+ header: 'Email',
137
+ },
138
+ {
139
+ accessorKey: 'role',
140
+ header: 'Role',
141
+ cell: ({ row }) => {
142
+ const role = row.getValue('role') as string;
143
+ return (
144
+ <Badge variant={role === 'admin' ? 'default' : 'secondary'}>
145
+ {role}
146
+ </Badge>
147
+ );
148
+ },
149
+ },
150
+ {
151
+ accessorKey: 'status',
152
+ header: 'Status',
153
+ cell: ({ row }) => {
154
+ const status = row.getValue('status') as string;
155
+ return (
156
+ <Badge
157
+ variant={
158
+ status === 'active'
159
+ ? 'default'
160
+ : status === 'inactive'
161
+ ? 'secondary'
162
+ : 'outline'
163
+ }
164
+ >
165
+ {status}
166
+ </Badge>
167
+ );
168
+ },
169
+ },
170
+ {
171
+ accessorKey: 'createdAt',
172
+ header: 'Created',
173
+ cell: ({ row }) => {
174
+ const date = row.getValue('createdAt') as string;
175
+ return new Date(date).toLocaleDateString();
176
+ },
177
+ },
178
+ {
179
+ id: 'actions',
180
+ cell: ({ row }) => {
181
+ const user = row.original;
182
+ return (
183
+ <div className="flex items-center gap-2">
184
+ <Button variant="ghost" size="sm">
185
+ <Edit className="h-4 w-4" />
186
+ </Button>
187
+ <Button variant="ghost" size="sm">
188
+ <Trash2 className="h-4 w-4" />
189
+ </Button>
190
+ <Button variant="ghost" size="sm">
191
+ <MoreHorizontal className="h-4 w-4" />
192
+ </Button>
193
+ </div>
194
+ );
195
+ },
196
+ },
197
+ ];
198
+
199
+ // Product columns
200
+ const productColumns: ColumnDef<Product>[] = [
201
+ {
202
+ accessorKey: 'name',
203
+ header: ({ column }) => (
204
+ <Button
205
+ variant="ghost"
206
+ onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
207
+ >
208
+ Product
209
+ <ArrowUpDown className="ml-2 h-4 w-4" />
210
+ </Button>
211
+ ),
212
+ },
213
+ {
214
+ accessorKey: 'category',
215
+ header: 'Category',
216
+ cell: ({ row }) => {
217
+ const category = row.getValue('category') as string;
218
+ return <Badge variant="outline">{category}</Badge>;
219
+ },
220
+ },
221
+ {
222
+ accessorKey: 'price',
223
+ header: ({ column }) => (
224
+ <Button
225
+ variant="ghost"
226
+ onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
227
+ >
228
+ Price
229
+ <ArrowUpDown className="ml-2 h-4 w-4" />
230
+ </Button>
231
+ ),
232
+ cell: ({ row }) => {
233
+ const price = parseFloat(row.getValue('price'));
234
+ return new Intl.NumberFormat('en-US', {
235
+ style: 'currency',
236
+ currency: 'USD',
237
+ }).format(price);
238
+ },
239
+ },
240
+ {
241
+ accessorKey: 'stock',
242
+ header: ({ column }) => (
243
+ <Button
244
+ variant="ghost"
245
+ onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
246
+ >
247
+ Stock
248
+ <ArrowUpDown className="ml-2 h-4 w-4" />
249
+ </Button>
250
+ ),
251
+ },
252
+ {
253
+ accessorKey: 'status',
254
+ header: 'Status',
255
+ cell: ({ row }) => {
256
+ const status = row.getValue('status') as string;
257
+ return (
258
+ <Badge
259
+ variant={
260
+ status === 'available'
261
+ ? 'default'
262
+ : status === 'out_of_stock'
263
+ ? 'secondary'
264
+ : 'outline'
265
+ }
266
+ >
267
+ {status.replace('_', ' ')}
268
+ </Badge>
269
+ );
270
+ },
271
+ },
272
+ ];
273
+
274
+ const meta: Meta<typeof DataTable> = {
275
+ title: 'Components/DataTable',
276
+ component: DataTable,
277
+ parameters: {
278
+ layout: 'fullscreen',
279
+ docs: {
280
+ description: {
281
+ component: 'A powerful data table component with sorting, filtering, and pagination.',
282
+ },
283
+ },
284
+ },
285
+ tags: ['autodocs'],
286
+ argTypes: {
287
+ columns: {
288
+ description: 'Column definitions for the table',
289
+ },
290
+ data: {
291
+ description: 'Data to display in the table',
292
+ },
293
+ searchable: {
294
+ control: 'boolean',
295
+ description: 'Enable search functionality',
296
+ },
297
+ filterable: {
298
+ control: 'boolean',
299
+ description: 'Enable column filtering',
300
+ },
301
+ exportable: {
302
+ control: 'boolean',
303
+ description: 'Enable data export',
304
+ },
305
+ },
306
+ };
307
+
308
+ export default meta;
309
+ type Story = StoryObj<typeof meta>;
310
+
311
+ export const Default: Story = {
312
+ args: {
313
+ columns: userColumns,
314
+ data: userData,
315
+ },
316
+ };
317
+
318
+ export const WithSearch: Story = {
319
+ args: {
320
+ columns: userColumns,
321
+ data: userData,
322
+ searchable: true,
323
+ },
324
+ };
325
+
326
+ export const WithFilters: Story = {
327
+ args: {
328
+ columns: userColumns,
329
+ data: userData,
330
+ searchable: true,
331
+ filterable: true,
332
+ },
333
+ };
334
+
335
+ export const WithExport: Story = {
336
+ args: {
337
+ columns: userColumns,
338
+ data: userData,
339
+ searchable: true,
340
+ filterable: true,
341
+ exportable: true,
342
+ },
343
+ };
344
+
345
+ export const ProductTable: Story = {
346
+ args: {
347
+ columns: productColumns,
348
+ data: productData,
349
+ searchable: true,
350
+ filterable: true,
351
+ },
352
+ };
353
+
354
+ export const LargeDataset: Story = {
355
+ args: {
356
+ columns: userColumns,
357
+ data: Array.from({ length: 50 }, (_, i) => ({
358
+ id: `${i + 1}`,
359
+ name: `User ${i + 1}`,
360
+ email: `user${i + 1}@example.com`,
361
+ role: ['admin', 'user', 'moderator'][i % 3] as 'admin' | 'user' | 'moderator',
362
+ status: ['active', 'inactive', 'pending'][i % 3] as 'active' | 'inactive' | 'pending',
363
+ createdAt: new Date(2023, Math.floor(i / 12), (i % 30) + 1).toISOString().split('T')[0],
364
+ lastLogin: new Date(2024, 0, (i % 15) + 1).toISOString().split('T')[0],
365
+ })),
366
+ searchable: true,
367
+ filterable: true,
368
+ exportable: true,
369
+ },
370
+ };
371
+
372
+ export const EmptyState: Story = {
373
+ args: {
374
+ columns: userColumns,
375
+ data: [],
376
+ searchable: true,
377
+ filterable: true,
378
+ },
379
+ };
380
+
381
+ export const SingleRow: Story = {
382
+ args: {
383
+ columns: userColumns,
384
+ data: [userData[0]],
385
+ searchable: true,
386
+ },
387
+ };
388
+
389
+ export const CustomPageSize: Story = {
390
+ args: {
391
+ columns: productColumns,
392
+ data: productData,
393
+ searchable: true,
394
+ filterable: true,
395
+ // Custom page size would be handled by the DataTable component
396
+ },
397
+ };
398
+
399
+ export const CompactTable: Story = {
400
+ args: {
401
+ columns: productColumns.map(col => ({
402
+ ...col,
403
+ // Add compact styling
404
+ })),
405
+ data: productData,
406
+ searchable: true,
407
+ // Compact prop would be handled by the DataTable component
408
+ },
409
+ };
410
+
411
+ export const InteractiveExample: Story = {
412
+ render: () => {
413
+ const columns: ColumnDef<User>[] = [
414
+ {
415
+ accessorKey: 'name',
416
+ header: ({ column }) => (
417
+ <Button
418
+ variant="ghost"
419
+ onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
420
+ >
421
+ Name
422
+ <ArrowUpDown className="ml-2 h-4 w-4" />
423
+ </Button>
424
+ ),
425
+ },
426
+ {
427
+ accessorKey: 'email',
428
+ header: 'Email',
429
+ },
430
+ {
431
+ accessorKey: 'role',
432
+ header: 'Role',
433
+ cell: ({ row }) => {
434
+ const role = row.getValue('role') as string;
435
+ return (
436
+ <Badge
437
+ variant={role === 'admin' ? 'default' : 'secondary'}
438
+ className="cursor-pointer"
439
+ onClick={() => alert(`Role: ${role}`)}
440
+ >
441
+ {role}
442
+ </Badge>
443
+ );
444
+ },
445
+ },
446
+ {
447
+ accessorKey: 'status',
448
+ header: 'Status',
449
+ cell: ({ row }) => {
450
+ const status = row.getValue('status') as string;
451
+ return (
452
+ <Badge
453
+ variant={
454
+ status === 'active'
455
+ ? 'default'
456
+ : status === 'inactive'
457
+ ? 'secondary'
458
+ : 'outline'
459
+ }
460
+ className="cursor-pointer"
461
+ onClick={() => alert(`Status: ${status}`)}
462
+ >
463
+ {status}
464
+ </Badge>
465
+ );
466
+ },
467
+ },
468
+ {
469
+ id: 'actions',
470
+ cell: ({ row }) => {
471
+ const user = row.original;
472
+ return (
473
+ <div className="flex items-center gap-2">
474
+ <Button
475
+ variant="ghost"
476
+ size="sm"
477
+ onClick={() => alert(`Edit user: ${user.name}`)}
478
+ >
479
+ <Edit className="h-4 w-4" />
480
+ </Button>
481
+ <Button
482
+ variant="ghost"
483
+ size="sm"
484
+ onClick={() => alert(`Delete user: ${user.name}`)}
485
+ >
486
+ <Trash2 className="h-4 w-4" />
487
+ </Button>
488
+ </div>
489
+ );
490
+ },
491
+ },
492
+ ];
493
+
494
+ return (
495
+ <div className="space-y-4">
496
+ <div className="text-sm text-muted-foreground">
497
+ Click on badges or action buttons to see interactions
498
+ </div>
499
+ <DataTable
500
+ columns={columns}
501
+ data={userData}
502
+ searchable={true}
503
+ filterable={true}
504
+ exportable={true}
505
+ />
506
+ </div>
507
+ );
508
+ },
509
+ };