@catalystsoftware/ui 1.0.5 → 1.0.7

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 (155) hide show
  1. package/dist/data/data.tsx +29 -29
  2. package/dist/data/tailwind.config.js +3821 -261
  3. package/dist/data.tsx +29 -29
  4. package/package.json +4 -3
  5. package/components/catalyst-ui/buttons/burger.tsx +0 -207
  6. package/components/catalyst-ui/core/data-display/timeline.tsx +0 -210
  7. package/components/catalyst-ui/core/feedback/alert.tsx +0 -491
  8. package/components/catalyst-ui/core/feedback/spinner-1.tsx +0 -65
  9. package/components/catalyst-ui/core/feedback/toast.tsx +0 -1857
  10. package/components/catalyst-ui/core/navigation/menu.tsx +0 -164
  11. package/components/catalyst-ui/forms/toggle-class.tsx +0 -176
  12. package/components/catalyst-ui/hooks/use-copy-to-clipboard.tsx +0 -419
  13. package/components/catalyst-ui/hooks/use-counter.tsx +0 -13
  14. package/components/catalyst-ui/hooks/use-event-listener.tsx +0 -23
  15. package/components/catalyst-ui/hooks/use-export-markdown.tsx +0 -47
  16. package/components/catalyst-ui/hooks/use-focus.tsx +0 -17
  17. package/components/catalyst-ui/hooks/use-interval.tsx +0 -23
  18. package/components/catalyst-ui/hooks/use-is-client.tsx +0 -16
  19. package/components/catalyst-ui/hooks/use-media-query.tsx +0 -19
  20. package/components/catalyst-ui/hooks/use-mobile.tsx +0 -19
  21. package/components/catalyst-ui/hooks/use-resize-observer.tsx +0 -81
  22. package/components/catalyst-ui/hooks/use-timeout.tsx +0 -21
  23. package/components/catalyst-ui/hooks/use-timer.tsx +0 -209
  24. package/components/catalyst-ui/hooks/use-toggle.tsx +0 -12
  25. package/components/catalyst-ui/media/image.tsx +0 -13
  26. package/components/catalyst-ui/overlays/dual-sidebar.tsx +0 -4142
  27. package/components/catalyst-ui/overlays/sidebar-original.tsx +0 -726
  28. package/components/catalyst-ui/primitives/accordion.tsx +0 -250
  29. package/components/catalyst-ui/primitives/alert-dialog.tsx +0 -126
  30. package/components/catalyst-ui/primitives/aspect-ratio.tsx +0 -9
  31. package/components/catalyst-ui/primitives/avatar.tsx +0 -296
  32. package/components/catalyst-ui/primitives/badge.tsx +0 -57
  33. package/components/catalyst-ui/primitives/breadcrumb.tsx +0 -101
  34. package/components/catalyst-ui/primitives/button.tsx +0 -265
  35. package/components/catalyst-ui/primitives/calendar-v4.tsx +0 -208
  36. package/components/catalyst-ui/primitives/calendar.tsx +0 -295
  37. package/components/catalyst-ui/primitives/card.tsx +0 -618
  38. package/components/catalyst-ui/primitives/carousel.tsx +0 -238
  39. package/components/catalyst-ui/primitives/chart.tsx +0 -347
  40. package/components/catalyst-ui/primitives/checkbox.tsx +0 -225
  41. package/components/catalyst-ui/primitives/collapsible.tsx +0 -212
  42. package/components/catalyst-ui/primitives/command.tsx +0 -393
  43. package/components/catalyst-ui/primitives/context-menu.tsx +0 -236
  44. package/components/catalyst-ui/primitives/dialog.tsx +0 -471
  45. package/components/catalyst-ui/primitives/drawer.tsx +0 -761
  46. package/components/catalyst-ui/primitives/dropdown-menu.tsx +0 -290
  47. package/components/catalyst-ui/primitives/empty.tsx +0 -104
  48. package/components/catalyst-ui/primitives/field.tsx +0 -244
  49. package/components/catalyst-ui/primitives/hover-card.tsx +0 -124
  50. package/components/catalyst-ui/primitives/input-otp.tsx +0 -76
  51. package/components/catalyst-ui/primitives/input.tsx +0 -64
  52. package/components/catalyst-ui/primitives/item.tsx +0 -196
  53. package/components/catalyst-ui/primitives/kbd.tsx +0 -75
  54. package/components/catalyst-ui/primitives/label.tsx +0 -24
  55. package/components/catalyst-ui/primitives/navigation-menu.tsx +0 -150
  56. package/components/catalyst-ui/primitives/pagination.tsx +0 -198
  57. package/components/catalyst-ui/primitives/popover.tsx +0 -232
  58. package/components/catalyst-ui/primitives/progress.tsx +0 -34
  59. package/components/catalyst-ui/primitives/radio-group.tsx +0 -43
  60. package/components/catalyst-ui/primitives/resizable.tsx +0 -56
  61. package/components/catalyst-ui/primitives/select.tsx +0 -155
  62. package/components/catalyst-ui/primitives/separator.tsx +0 -74
  63. package/components/catalyst-ui/primitives/sheet.tsx +0 -126
  64. package/components/catalyst-ui/primitives/skeleton.tsx +0 -15
  65. package/components/catalyst-ui/primitives/slider.tsx +0 -27
  66. package/components/catalyst-ui/primitives/switch.tsx +0 -187
  67. package/components/catalyst-ui/primitives/tabs.tsx +0 -335
  68. package/components/catalyst-ui/primitives/textarea.tsx +0 -24
  69. package/components/catalyst-ui/primitives/toggle-group.tsx +0 -55
  70. package/components/catalyst-ui/primitives/toggle.tsx +0 -42
  71. package/components/catalyst-ui/primitives/tooltip.tsx +0 -116
  72. package/components/catalyst-ui/utils/basic-auth.tsx +0 -40
  73. package/components/catalyst-ui/utils/context-storage.tsx +0 -19
  74. package/components/catalyst-ui/utils/cors-middleware.tsx +0 -71
  75. package/components/catalyst-ui/utils/deferred-content.tsx +0 -595
  76. package/components/catalyst-ui/utils/honeypot-middleware.tsx +0 -38
  77. package/components/catalyst-ui/utils/incId.tsx +0 -75
  78. package/components/catalyst-ui/utils/jwk-auth.tsx +0 -36
  79. package/components/catalyst-ui/utils/request-id.tsx +0 -14
  80. package/components/catalyst-ui/utils/secure-headers.tsx +0 -37
  81. package/components/catalyst-ui/utils/server-timing.tsx +0 -23
  82. package/components/catalyst-ui/utils/utils.ts +0 -43
  83. package/components/catalyst-ui/utils/with-cookie.tsx +0 -43
  84. package/components/catalyst-ui/x/accordian-x.tsx +0 -428
  85. package/components/catalyst-ui/x/alert-x.tsx +0 -413
  86. package/components/catalyst-ui/x/animated-text-x.tsx +0 -2242
  87. package/components/catalyst-ui/x/avatar-x.tsx +0 -515
  88. package/components/catalyst-ui/x/badge-x.tsx +0 -670
  89. package/components/catalyst-ui/x/button-X.tsx +0 -2857
  90. package/components/catalyst-ui/x/button-group-x.tsx +0 -847
  91. package/components/catalyst-ui/x/calendar-x.tsx +0 -1910
  92. package/components/catalyst-ui/x/card-x.tsx +0 -2597
  93. package/components/catalyst-ui/x/checkbox-x.tsx +0 -656
  94. package/components/catalyst-ui/x/collapsible-x.tsx +0 -1360
  95. package/components/catalyst-ui/x/combobox-x.tsx +0 -911
  96. package/components/catalyst-ui/x/data-table-x.tsx +0 -1753
  97. package/components/catalyst-ui/x/date-picker-x.tsx +0 -648
  98. package/components/catalyst-ui/x/dialog-x.tsx +0 -659
  99. package/components/catalyst-ui/x/dropdown-menu-x.tsx +0 -612
  100. package/components/catalyst-ui/x/hover-card-x.tsx +0 -375
  101. package/components/catalyst-ui/x/icon-x.tsx +0 -840
  102. package/components/catalyst-ui/x/input-mask-x.tsx +0 -981
  103. package/components/catalyst-ui/x/input-otp-x.tsx +0 -659
  104. package/components/catalyst-ui/x/loader-x.tsx +0 -1757
  105. package/components/catalyst-ui/x/pagination-x.tsx +0 -622
  106. package/components/catalyst-ui/x/popover-x.tsx +0 -744
  107. package/components/catalyst-ui/x/radio-group-x.tsx +0 -499
  108. package/components/catalyst-ui/x/select-x.tsx +0 -1127
  109. package/components/catalyst-ui/x/sheet-x.tsx +0 -668
  110. package/components/catalyst-ui/x/switch-x.tsx +0 -681
  111. package/components/catalyst-ui/x/table-x.tsx +0 -574
  112. package/components/catalyst-ui/x/tabs-x.tsx +0 -839
  113. package/components/catalyst-ui/x/textarea-x.tsx +0 -1263
  114. package/components/catalyst-ui/x/tooltip-x.tsx +0 -396
  115. package/components/catalyst-ui/x/tracker-x.tsx +0 -560
  116. package/data/bg-data.tsx +0 -901
  117. package/data/buttons-data.tsx +0 -2327
  118. package/data/charts-data.tsx +0 -102
  119. package/data/chat-data.tsx +0 -83
  120. package/data/code-data.tsx +0 -1040
  121. package/data/comboboxes-data.tsx +0 -1843
  122. package/data/command-data.tsx +0 -1381
  123. package/data/core-data.tsx +0 -15953
  124. package/data/crm-data.tsx +0 -47
  125. package/data/data.tsx +0 -159
  126. package/data/date-and-time-data.tsx +0 -554
  127. package/data/dependencies.tsx +0 -7
  128. package/data/ecommerce-data.tsx +0 -1387
  129. package/data/forms-data.tsx +0 -7890
  130. package/data/hooks-data.tsx +0 -5487
  131. package/data/index.ts +0 -34
  132. package/data/inputs-data.tsx +0 -557
  133. package/data/interactive-data.tsx +0 -5394
  134. package/data/lofi-data.tsx +0 -18295
  135. package/data/marketing-data.tsx +0 -2546
  136. package/data/media-data.tsx +0 -1510
  137. package/data/motion-data.tsx +0 -5801
  138. package/data/overlay-data.tsx +0 -4136
  139. package/data/pdf-data.tsx +0 -124
  140. package/data/pos-data.tsx +0 -213
  141. package/data/postcss.config.js +0 -6
  142. package/data/primitive-data.tsx +0 -5170
  143. package/data/prompt-data.tsx +0 -1226
  144. package/data/requiredLibs.ts +0 -4
  145. package/data/sandbox-data.tsx +0 -1
  146. package/data/sidebars-data.tsx +0 -5421
  147. package/data/stacks-data.tsx +0 -32
  148. package/data/table-data.tsx +0 -706
  149. package/data/tailwind.config.js +0 -270
  150. package/data/tailwind.config.ngin.js +0 -3830
  151. package/data/tailwind.css +0 -431
  152. package/data/tools-data.tsx +0 -6910
  153. package/data/typography-data.tsx +0 -2050
  154. package/data/utils-data.tsx +0 -6500
  155. package/data/x-data.tsx +0 -1171
@@ -1,1753 +0,0 @@
1
- /**
2
-
3
-
4
-
5
-
6
-
7
-
8
- export function DataTableX({ dataTable = 'default', children, ...props }: any) {
9
- switch (dataTable) {
10
- case 'Closable':
11
- break
12
- default:
13
- break;
14
- }
15
- }
16
-
17
- const DataTableDemo = () => {
18
- const [sorting, setSorting] = useState<SortingState>([])
19
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
20
- const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
21
- const [rowSelection, setRowSelection] = useState({})
22
-
23
- const table = useReactTable({
24
- data,
25
- columns,
26
- onSortingChange: setSorting,
27
- onColumnFiltersChange: setColumnFilters,
28
- getCoreRowModel: getCoreRowModel(),
29
- getPaginationRowModel: getPaginationRowModel(),
30
- getSortedRowModel: getSortedRowModel(),
31
- getFilteredRowModel: getFilteredRowModel(),
32
- onColumnVisibilityChange: setColumnVisibility,
33
- onRowSelectionChange: setRowSelection,
34
- state: {
35
- sorting,
36
- columnFilters,
37
- columnVisibility,
38
- rowSelection
39
- }
40
- })
41
-
42
- return (
43
- <div className='w-full'>
44
- <div className='rounded-md border'>
45
- <Table>
46
- <TableHeader>
47
- {table.getHeaderGroups().map(headerGroup => (
48
- <TableRow key={headerGroup.id}>
49
- {headerGroup.headers.map(header => {
50
- return (
51
- <TableHead key={header.id}>
52
- {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
53
- </TableHead>
54
- )
55
- })}
56
- </TableRow>
57
- ))}
58
- </TableHeader>
59
- <TableBody>
60
- {table.getRowModel().rows?.length ? (
61
- table.getRowModel().rows.map(row => (
62
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
63
- {row.getVisibleCells().map(cell => (
64
- <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
65
- ))}
66
- </TableRow>
67
- ))
68
- ) : (
69
- <TableRow>
70
- <TableCell colSpan={columns.length} className='h-24 text-center'>
71
- No results.
72
- </TableCell>
73
- </TableRow>
74
- )}
75
- </TableBody>
76
- </Table>
77
- </div>
78
- <p className='text-muted-foreground mt-4 text-center text-sm'>Default data table</p>
79
- </div>
80
- )
81
- }
82
-
83
- const DataTableDensityDemo = () => {
84
- const [density, setDensity] = useState<string>()
85
- const [sorting, setSorting] = useState<SortingState>([])
86
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
87
- const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
88
- const [rowSelection, setRowSelection] = useState({})
89
-
90
- const table = useReactTable({
91
- data,
92
- columns,
93
- onSortingChange: setSorting,
94
- onColumnFiltersChange: setColumnFilters,
95
- getCoreRowModel: getCoreRowModel(),
96
- getPaginationRowModel: getPaginationRowModel(),
97
- getSortedRowModel: getSortedRowModel(),
98
- getFilteredRowModel: getFilteredRowModel(),
99
- onColumnVisibilityChange: setColumnVisibility,
100
- onRowSelectionChange: setRowSelection,
101
- state: {
102
- sorting,
103
- columnFilters,
104
- columnVisibility,
105
- rowSelection
106
- }
107
- })
108
-
109
- return (
110
- <div className='w-full'>
111
- <div className='py-4'>
112
- <Select value={density} onValueChange={setDensity}>
113
- <SelectTrigger className='w-full max-w-3xs' aria-label='Density select'>
114
- <SelectValue placeholder='Density' />
115
- </SelectTrigger>
116
- <SelectContent>
117
- <SelectGroup>
118
- <SelectLabel>Density</SelectLabel>
119
- <SelectItem value='compact'>
120
- <div className='flex items-center gap-2'>
121
- <Rows4Icon className='size-4' />
122
- Compact
123
- </div>
124
- </SelectItem>
125
- <SelectItem value='standard' className='flex items-center gap-2'>
126
- <div className='flex items-center gap-2'>
127
- <Rows3Icon className='size-4' /> Standard
128
- </div>
129
- </SelectItem>
130
- <SelectItem value='flexible' className='flex items-center gap-2'>
131
- <div className='flex items-center gap-2'>
132
- <Rows2Icon className='size-4' />
133
- Flexible
134
- </div>
135
- </SelectItem>
136
- </SelectGroup>
137
- </SelectContent>
138
- </Select>
139
- </div>
140
- <div className='rounded-md border'>
141
- <Table
142
- className={cn({
143
- '[&_td]:py-px [&_th]:py-px': density === 'compact',
144
- '[&_td]:py-1 [&_th]:py-1': density === 'standard',
145
- '[&_td]:py-2 [&_th]:py-1': density === 'flexible'
146
- })}
147
- >
148
- <TableHeader>
149
- {table.getHeaderGroups().map(headerGroup => (
150
- <TableRow key={headerGroup.id}>
151
- {headerGroup.headers.map(header => {
152
- return (
153
- <TableHead key={header.id}>
154
- {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
155
- </TableHead>
156
- )
157
- })}
158
- </TableRow>
159
- ))}
160
- </TableHeader>
161
- <TableBody>
162
- {table.getRowModel().rows?.length ? (
163
- table.getRowModel().rows.map(row => (
164
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
165
- {row.getVisibleCells().map(cell => (
166
- <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
167
- ))}
168
- </TableRow>
169
- ))
170
- ) : (
171
- <TableRow>
172
- <TableCell colSpan={columns.length} className='h-24 text-center'>
173
- No results.
174
- </TableCell>
175
- </TableRow>
176
- )}
177
- </TableBody>
178
- </Table>
179
- </div>
180
- <p className='text-muted-foreground mt-4 text-center text-sm'>
181
- Density data table{' '}
182
- <a
183
- href='https://www.shadcnui-blocks.com/components/table'
184
- className='hover:text-primary underline'
185
- target='_blank'
186
- >
187
- Shadcn UI Blocks
188
- </a>
189
- </p>
190
- </div>
191
- )
192
- }
193
-
194
- const DataTableColumnsVisibilityDemo = () => {
195
- const [searchQuery, setSearchQuery] = useState<string>('')
196
- const [sorting, setSorting] = useState<SortingState>([])
197
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
198
- const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
199
- const [rowSelection, setRowSelection] = useState({})
200
-
201
- const table = useReactTable({
202
- data,
203
- columns,
204
- onSortingChange: setSorting,
205
- onColumnFiltersChange: setColumnFilters,
206
- getCoreRowModel: getCoreRowModel(),
207
- getPaginationRowModel: getPaginationRowModel(),
208
- getSortedRowModel: getSortedRowModel(),
209
- getFilteredRowModel: getFilteredRowModel(),
210
- onColumnVisibilityChange: setColumnVisibility,
211
- onRowSelectionChange: setRowSelection,
212
- state: {
213
- sorting,
214
- columnFilters,
215
- columnVisibility,
216
- rowSelection
217
- }
218
- })
219
-
220
- return (
221
- <div className='w-full'>
222
- <div className='py-4'>
223
- <DropdownMenu>
224
- <DropdownMenuTrigger asChild>
225
- <Button variant='outline' className='w-full max-w-3xs justify-between'>
226
- <span className='flex items-center gap-2'>
227
- <Columns3Icon />
228
- Columns
229
- </span>{' '}
230
- <ChevronDownIcon className='ml-3' />
231
- </Button>
232
- </DropdownMenuTrigger>
233
- <DropdownMenuContent align='end'>
234
- <div className='relative'>
235
- <Input
236
- value={searchQuery}
237
- onChange={e => setSearchQuery(e.target.value)}
238
- className='pl-8'
239
- placeholder='Search'
240
- onKeyDown={e => e.stopPropagation()}
241
- />
242
- <SearchIcon className='absolute inset-y-0 left-2 my-auto size-4' />
243
- </div>
244
- <DropdownMenuSeparator />
245
- {table
246
- .getAllColumns()
247
- .filter(column => column.getCanHide())
248
- .map(column => {
249
- if (searchQuery && !column.id.toLowerCase().includes(searchQuery.toLowerCase())) {
250
- return null
251
- }
252
-
253
- return (
254
- <DropdownMenuCheckboxItem
255
- key={column.id}
256
- className='capitalize'
257
- checked={column.getIsVisible()}
258
- onCheckedChange={value => column.toggleVisibility(!!value)}
259
- onSelect={e => e.preventDefault()}
260
- >
261
- {column.id}
262
- </DropdownMenuCheckboxItem>
263
- )
264
- })}
265
- <DropdownMenuSeparator />
266
- <DropdownMenuItem
267
- onClick={() => {
268
- table.resetColumnVisibility()
269
- setSearchQuery('')
270
- }}
271
- >
272
- <RefreshCcwIcon /> Reset
273
- </DropdownMenuItem>
274
- </DropdownMenuContent>
275
- </DropdownMenu>
276
- </div>
277
- <div className='rounded-md border'>
278
- <Table>
279
- <TableHeader>
280
- {table.getHeaderGroups().map(headerGroup => (
281
- <TableRow key={headerGroup.id}>
282
- {headerGroup.headers.map(header => {
283
- return (
284
- <TableHead key={header.id}>
285
- {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
286
- </TableHead>
287
- )
288
- })}
289
- </TableRow>
290
- ))}
291
- </TableHeader>
292
- <TableBody>
293
- {table.getRowModel().rows?.length ? (
294
- table.getRowModel().rows.map(row => (
295
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
296
- {row.getVisibleCells().map(cell => (
297
- <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
298
- ))}
299
- </TableRow>
300
- ))
301
- ) : (
302
- <TableRow>
303
- <TableCell colSpan={columns.length} className='h-24 text-center'>
304
- No results.
305
- </TableCell>
306
- </TableRow>
307
- )}
308
- </TableBody>
309
- </Table>
310
- </div>
311
- <p className='text-muted-foreground mt-4 text-center text-sm'>Data table column visibility</p>
312
- </div>
313
- )
314
- }
315
-
316
- const DataTableWithColumnFilterDemo = () => {
317
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
318
-
319
- const [sorting, setSorting] = useState<SortingState>([
320
- {
321
- id: 'price',
322
- desc: false
323
- }
324
- ])
325
-
326
- const table = useReactTable({
327
- data: items,
328
- columns,
329
- state: {
330
- sorting,
331
- columnFilters
332
- },
333
- onColumnFiltersChange: setColumnFilters,
334
- getCoreRowModel: getCoreRowModel(),
335
- getFilteredRowModel: getFilteredRowModel(),
336
- getSortedRowModel: getSortedRowModel(),
337
- getFacetedRowModel: getFacetedRowModel(),
338
- getFacetedUniqueValues: getFacetedUniqueValues(),
339
- getFacetedMinMaxValues: getFacetedMinMaxValues(),
340
- onSortingChange: setSorting,
341
- enableSortingRemoval: false
342
- })
343
-
344
- return (
345
- <div className='w-full'>
346
- <div className='rounded-md border'>
347
- <div className='flex flex-wrap gap-3 px-2 py-6'>
348
- <div className='w-44'>
349
- <Filter column={table.getColumn('product')!} />
350
- </div>
351
- <div className='w-36'>
352
- <Filter column={table.getColumn('price')!} />
353
- </div>
354
- <div className='w-44'>
355
- <Filter column={table.getColumn('availability')!} />
356
- </div>
357
- <div className='w-36'>
358
- <Filter column={table.getColumn('rating')!} />
359
- </div>
360
- </div>
361
- <Table>
362
- <TableHeader>
363
- {table.getHeaderGroups().map(headerGroup => (
364
- <TableRow key={headerGroup.id} className='bg-muted/50'>
365
- {headerGroup.headers.map(header => {
366
- return (
367
- <TableHead key={header.id} className='relative h-10 border-t select-none'>
368
- {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
369
- </TableHead>
370
- )
371
- })}
372
- </TableRow>
373
- ))}
374
- </TableHeader>
375
- <TableBody>
376
- {table.getRowModel().rows?.length ? (
377
- table.getRowModel().rows.map(row => (
378
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
379
- {row.getVisibleCells().map(cell => (
380
- <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
381
- ))}
382
- </TableRow>
383
- ))
384
- ) : (
385
- <TableRow>
386
- <TableCell colSpan={columns.length} className='h-24 text-center'>
387
- No results.
388
- </TableCell>
389
- </TableRow>
390
- )}
391
- </TableBody>
392
- </Table>
393
- </div>
394
-
395
- <p className='text-muted-foreground mt-4 text-center text-sm'>Data table with column filter</p>
396
- </div>
397
- )
398
- }
399
-
400
- const DataTableWithSortableColumnDemo = () => {
401
- const [sorting, setSorting] = useState<SortingState>([])
402
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
403
- const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
404
- const [rowSelection, setRowSelection] = useState({})
405
-
406
- const table = useReactTable({
407
- data,
408
- columns,
409
- onSortingChange: setSorting,
410
- onColumnFiltersChange: setColumnFilters,
411
- getCoreRowModel: getCoreRowModel(),
412
- getPaginationRowModel: getPaginationRowModel(),
413
- getSortedRowModel: getSortedRowModel(),
414
- getFilteredRowModel: getFilteredRowModel(),
415
- onColumnVisibilityChange: setColumnVisibility,
416
- onRowSelectionChange: setRowSelection,
417
- state: {
418
- sorting,
419
- columnFilters,
420
- columnVisibility,
421
- rowSelection
422
- }
423
- })
424
-
425
- return (
426
- <div className='w-full'>
427
- <div className='rounded-md border'>
428
- <Table>
429
- <TableHeader>
430
- {table.getHeaderGroups().map(headerGroup => (
431
- <TableRow key={headerGroup.id}>
432
- {headerGroup.headers.map(header => {
433
- return (
434
- <TableHead
435
- key={header.id}
436
- aria-sort={
437
- header.column.getIsSorted() === 'asc'
438
- ? 'ascending'
439
- : header.column.getIsSorted() === 'desc'
440
- ? 'descending'
441
- : 'none'
442
- }
443
- >
444
- {header.isPlaceholder ? null : (
445
- <div
446
- className={cn(
447
- header.column.getCanSort() &&
448
- 'flex h-full cursor-pointer items-center justify-between gap-2 select-none'
449
- )}
450
- onClick={header.column.getToggleSortingHandler()}
451
- onKeyDown={e => {
452
- if (header.column.getCanSort() && (e.key === 'Enter' || e.key === ' ')) {
453
- e.preventDefault()
454
- header.column.getToggleSortingHandler()?.(e)
455
- }
456
- }}
457
- tabIndex={header.column.getCanSort() ? 0 : undefined}
458
- >
459
- <span className='truncate'>
460
- {flexRender(header.column.columnDef.header, header.getContext())}
461
- </span>
462
- {{
463
- asc: <ChevronUpIcon className='shrink-0 opacity-60' size={16} aria-hidden='true' />,
464
- desc: <ChevronDownIcon className='shrink-0 opacity-60' size={16} aria-hidden='true' />
465
- }[header.column.getIsSorted() as string] ?? null}
466
- </div>
467
- )}
468
- </TableHead>
469
- )
470
- })}
471
- </TableRow>
472
- ))}
473
- </TableHeader>
474
- <TableBody>
475
- {table.getRowModel().rows?.length ? (
476
- table.getRowModel().rows.map(row => (
477
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
478
- {row.getVisibleCells().map(cell => (
479
- <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
480
- ))}
481
- </TableRow>
482
- ))
483
- ) : (
484
- <TableRow>
485
- <TableCell colSpan={columns.length} className='h-24 text-center'>
486
- No results.
487
- </TableCell>
488
- </TableRow>
489
- )}
490
- </TableBody>
491
- </Table>
492
- </div>
493
- <p className='text-muted-foreground mt-4 text-center text-sm'>Data table with sortable column</p>
494
- </div>
495
- )
496
- }
497
-
498
- const DataTableWithResizableColumnsDemo = () => {
499
- const [sorting, setSorting] = useState<SortingState>([])
500
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
501
- const [rowSelection, setRowSelection] = useState({})
502
-
503
- const table = useReactTable({
504
- data,
505
- columns,
506
- columnResizeMode: 'onChange',
507
- onSortingChange: setSorting,
508
- onColumnFiltersChange: setColumnFilters,
509
- getCoreRowModel: getCoreRowModel(),
510
- onRowSelectionChange: setRowSelection,
511
- state: {
512
- sorting,
513
- columnFilters,
514
- rowSelection
515
- }
516
- })
517
-
518
- return (
519
- <div className='max-w-3xl max-md:max-w-full'>
520
- <div className='rounded-md border'>
521
- <Table
522
- className='table-fixed'
523
- style={{
524
- width: table.getCenterTotalSize()
525
- }}
526
- >
527
- <TableHeader>
528
- {table.getHeaderGroups().map(headerGroup => (
529
- <TableRow key={headerGroup.id}>
530
- {headerGroup.headers.map(header => {
531
- return (
532
- <TableHead
533
- key={header.id}
534
- className='group/head relative h-10 select-none last:[&>.cursor-col-resize]:opacity-0'
535
- {...{
536
- colSpan: header.colSpan,
537
- style: {
538
- width: header.getSize()
539
- }
540
- }}
541
- >
542
- {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
543
- {header.column.getCanResize() && (
544
- <div
545
- {...{
546
- onDoubleClick: () => header.column.resetSize(),
547
- onMouseDown: header.getResizeHandler(),
548
- onTouchStart: header.getResizeHandler(),
549
- className:
550
- 'group-last/head:hidden absolute top-0 h-full w-4 cursor-col-resize user-select-none touch-none -right-2 z-10 flex justify-center before:absolute before:w-px before:inset-y-0 before:bg-border before:translate-x-px'
551
- }}
552
- />
553
- )}
554
- </TableHead>
555
- )
556
- })}
557
- </TableRow>
558
- ))}
559
- </TableHeader>
560
- <TableBody>
561
- {table.getRowModel().rows?.length ? (
562
- table.getRowModel().rows.map(row => (
563
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
564
- {row.getVisibleCells().map(cell => (
565
- <TableCell key={cell.id} className='truncate'>
566
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
567
- </TableCell>
568
- ))}
569
- </TableRow>
570
- ))
571
- ) : (
572
- <TableRow>
573
- <TableCell colSpan={columns.length} className='h-24 text-center'>
574
- No results.
575
- </TableCell>
576
- </TableRow>
577
- )}
578
- </TableBody>
579
- </Table>
580
- </div>
581
- <p className='text-muted-foreground mt-4 text-center text-sm'>Data table with resizable columns</p>
582
- </div>
583
- )
584
- }
585
-
586
- const DataTablePinnableColumnDemo = () => {
587
- const [sorting, setSorting] = useState<SortingState>([])
588
-
589
- const table = useReactTable({
590
- data,
591
- columns,
592
- getCoreRowModel: getCoreRowModel(),
593
- getSortedRowModel: getSortedRowModel(),
594
- onSortingChange: setSorting,
595
- state: {
596
- sorting
597
- },
598
- enableSortingRemoval: false
599
- })
600
-
601
- return (
602
- <div className='w-full'>
603
- <div className='rounded-md border'>
604
- <Table className='[&_td]:border-border [&_th]:border-border border-separate border-spacing-0 [&_tfoot_td]:border-t [&_th]:border-b [&_tr]:border-none [&_tr:not(:last-child)_td]:border-b'>
605
- <TableHeader>
606
- {table.getHeaderGroups().map(headerGroup => (
607
- <TableRow key={headerGroup.id}>
608
- {headerGroup.headers.map(header => {
609
- const { column } = header
610
- const isPinned = column.getIsPinned()
611
- const isLastLeftPinned = isPinned === 'left' && column.getIsLastColumn('left')
612
- const isFirstRightPinned = isPinned === 'right' && column.getIsFirstColumn('right')
613
-
614
- return (
615
- <TableHead
616
- key={header.id}
617
- className='data-pinned:bg-muted/90 relative h-10 truncate data-pinned:backdrop-blur-xs [&:not([data-pinned]):has(+[data-pinned])_div.cursor-col-resize:last-child]:opacity-0 [&[data-last-col=left]_div.cursor-col-resize:last-child]:opacity-0 [&[data-pinned=right]:last-child_div.cursor-col-resize:last-child]:opacity-0'
618
- colSpan={header.colSpan}
619
- style={{ ...getPinningStyles(column) }}
620
- data-pinned={isPinned || undefined}
621
- data-last-col={isLastLeftPinned ? 'left' : isFirstRightPinned ? 'right' : undefined}
622
- >
623
- <div className='flex items-center justify-between gap-2'>
624
- <span className='truncate'>
625
- {header.isPlaceholder
626
- ? null
627
- : flexRender(header.column.columnDef.header, header.getContext())}
628
- </span>
629
-
630
- {!header.isPlaceholder &&
631
- header.column.getCanPin() &&
632
- (header.column.getIsPinned() ? (
633
- <Button
634
- size='icon'
635
- variant='ghost'
636
- className='-mr-1 size-7'
637
- onClick={() => header.column.pin(false)}
638
- aria-label={`Unpin ${header.column.columnDef.header as string} column`}
639
- title={`Unpin ${header.column.columnDef.header as string} column`}
640
- >
641
- <PinOffIcon className='opacity-60' aria-hidden='true' />
642
- </Button>
643
- ) : (
644
- <DropdownMenu>
645
- <DropdownMenuTrigger asChild>
646
- <Button
647
- size='icon'
648
- variant='ghost'
649
- className='-mr-1 size-7'
650
- aria-label={`Pin options for ${header.column.columnDef.header as string} column`}
651
- title={`Pin options for ${header.column.columnDef.header as string} column`}
652
- >
653
- <EllipsisIcon className='opacity-60' aria-hidden='true' />
654
- </Button>
655
- </DropdownMenuTrigger>
656
- <DropdownMenuContent align='end'>
657
- <DropdownMenuItem onClick={() => header.column.pin('left')}>
658
- <ArrowLeftFromLineIcon size={16} className='opacity-60' aria-hidden='true' />
659
- Stick to left
660
- </DropdownMenuItem>
661
- <DropdownMenuItem onClick={() => header.column.pin('right')}>
662
- <ArrowRightFromLineIcon size={16} className='opacity-60' aria-hidden='true' />
663
- Stick to right
664
- </DropdownMenuItem>
665
- </DropdownMenuContent>
666
- </DropdownMenu>
667
- ))}
668
- </div>
669
- </TableHead>
670
- )
671
- })}
672
- </TableRow>
673
- ))}
674
- </TableHeader>
675
- <TableBody>
676
- {table.getRowModel().rows?.length ? (
677
- table.getRowModel().rows.map(row => (
678
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
679
- {row.getVisibleCells().map(cell => {
680
- const { column } = cell
681
- const isPinned = column.getIsPinned()
682
- const isLastLeftPinned = isPinned === 'left' && column.getIsLastColumn('left')
683
- const isFirstRightPinned = isPinned === 'right' && column.getIsFirstColumn('right')
684
-
685
- return (
686
- <TableCell
687
- key={cell.id}
688
- className='data-pinned:bg-background/90 truncate data-pinned:backdrop-blur-xs'
689
- style={{ ...getPinningStyles(column) }}
690
- data-pinned={isPinned || undefined}
691
- data-last-col={isLastLeftPinned ? 'left' : isFirstRightPinned ? 'right' : undefined}
692
- >
693
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
694
- </TableCell>
695
- )
696
- })}
697
- </TableRow>
698
- ))
699
- ) : (
700
- <TableRow>
701
- <TableCell colSpan={columns.length} className='h-24 text-center'>
702
- No results.
703
- </TableCell>
704
- </TableRow>
705
- )}
706
- </TableBody>
707
- </Table>
708
- </div>
709
- <p className='text-muted-foreground mt-4 text-center text-sm'>Data table with pinnable columns</p>
710
- </div>
711
- )
712
- }
713
-
714
- const DraggableColumnDataTableDemo = () => {
715
- const [sorting, setSorting] = useState<SortingState>([])
716
- const [columnOrder, setColumnOrder] = useState<string[]>(columns.map(column => column.id as string))
717
-
718
- const table = useReactTable({
719
- data,
720
- columns,
721
- columnResizeMode: 'onChange',
722
- getCoreRowModel: getCoreRowModel(),
723
- getSortedRowModel: getSortedRowModel(),
724
- onSortingChange: setSorting,
725
- state: {
726
- sorting,
727
- columnOrder
728
- },
729
- onColumnOrderChange: setColumnOrder,
730
- enableSortingRemoval: false
731
- })
732
-
733
- function handleDragEnd(event: DragEndEvent) {
734
- const { active, over } = event
735
-
736
- if (active && over && active.id !== over.id) {
737
- setColumnOrder(columnOrder => {
738
- const oldIndex = columnOrder.indexOf(active.id as string)
739
- const newIndex = columnOrder.indexOf(over.id as string)
740
-
741
- return arrayMove(columnOrder, oldIndex, newIndex)
742
- })
743
- }
744
- }
745
-
746
- const sensors = useSensors(useSensor(MouseSensor, {}), useSensor(TouchSensor, {}), useSensor(KeyboardSensor, {}))
747
-
748
- return (
749
- <div className='w-full'>
750
- <div className='rounded-md border'>
751
- <DndContext
752
- id={useId()}
753
- collisionDetection={closestCenter}
754
- modifiers={[restrictToHorizontalAxis]}
755
- onDragEnd={handleDragEnd}
756
- sensors={sensors}
757
- >
758
- <Table>
759
- <TableHeader>
760
- {table.getHeaderGroups().map(headerGroup => (
761
- <TableRow key={headerGroup.id} className='bg-muted/50 [&>th]:border-t-0'>
762
- <SortableContext items={columnOrder} strategy={horizontalListSortingStrategy}>
763
- {headerGroup.headers.map(header => (
764
- <DraggableTableHeader key={header.id} header={header} />
765
- ))}
766
- </SortableContext>
767
- </TableRow>
768
- ))}
769
- </TableHeader>
770
- <TableBody>
771
- {table.getRowModel().rows?.length ? (
772
- table.getRowModel().rows.map(row => (
773
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
774
- {row.getVisibleCells().map(cell => (
775
- <SortableContext key={cell.id} items={columnOrder} strategy={horizontalListSortingStrategy}>
776
- <DragAlongCell key={cell.id} cell={cell} />
777
- </SortableContext>
778
- ))}
779
- </TableRow>
780
- ))
781
- ) : (
782
- <TableRow>
783
- <TableCell colSpan={columns.length} className='h-24 text-center'>
784
- No results.
785
- </TableCell>
786
- </TableRow>
787
- )}
788
- </TableBody>
789
- </Table>
790
- </DndContext>
791
- </div>
792
- <p className='text-muted-foreground mt-4 text-center text-sm'>Data table with draggable columns</p>
793
- </div>
794
- )
795
- }
796
-
797
- const DraggableTableHeader = ({ header }: { header: Header<Employee, unknown> }) => {
798
- const { attributes, isDragging, listeners, setNodeRef, transform, transition } = useSortable({
799
- id: header.column.id
800
- })
801
-
802
- const style: CSSProperties = {
803
- opacity: isDragging ? 0.8 : 1,
804
- position: 'relative',
805
- transform: CSS.Translate.toString(transform),
806
- transition,
807
- whiteSpace: 'nowrap',
808
- width: header.column.getSize(),
809
- zIndex: isDragging ? 1 : 0
810
- }
811
-
812
- return (
813
- <TableHead
814
- ref={setNodeRef}
815
- className='before:bg-border relative h-10 border-t before:absolute before:inset-y-0 before:left-0 before:w-px first:before:bg-transparent'
816
- style={style}
817
- aria-sort={
818
- header.column.getIsSorted() === 'asc'
819
- ? 'ascending'
820
- : header.column.getIsSorted() === 'desc'
821
- ? 'descending'
822
- : 'none'
823
- }
824
- >
825
- <div className='flex items-center justify-start gap-0.5'>
826
- <Button
827
- size='icon'
828
- variant='ghost'
829
- className='-ml-2 size-7'
830
- {...attributes}
831
- {...listeners}
832
- aria-label='Drag to reorder'
833
- >
834
- <GripVerticalIcon className='opacity-60' aria-hidden='true' />
835
- </Button>
836
- <span className='grow truncate'>
837
- {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
838
- </span>
839
- <Button
840
- size='icon'
841
- variant='ghost'
842
- className='group -mr-1 size-7'
843
- onClick={header.column.getToggleSortingHandler()}
844
- onKeyDown={e => {
845
- if (header.column.getCanSort() && (e.key === 'Enter' || e.key === ' ')) {
846
- e.preventDefault()
847
- header.column.getToggleSortingHandler()?.(e)
848
- }
849
- }}
850
- aria-label='Toggle sorting'
851
- >
852
- {{
853
- asc: <ChevronUpIcon className='shrink-0 opacity-60' size={16} aria-hidden='true' />,
854
- desc: <ChevronDownIcon className='shrink-0 opacity-60' size={16} aria-hidden='true' />
855
- }[header.column.getIsSorted() as string] ?? (
856
- <ChevronUpIcon className='shrink-0 opacity-0 group-hover:opacity-60' size={16} aria-hidden='true' />
857
- )}
858
- </Button>
859
- </div>
860
- </TableHead>
861
- )
862
- }
863
-
864
- const DragAlongCell = ({ cell }: { cell: Cell<Employee, unknown> }) => {
865
- const { isDragging, setNodeRef, transform, transition } = useSortable({
866
- id: cell.column.id
867
- })
868
-
869
- const style: CSSProperties = {
870
- opacity: isDragging ? 0.8 : 1,
871
- position: 'relative',
872
- transform: CSS.Translate.toString(transform),
873
- transition,
874
- width: cell.column.getSize(),
875
- zIndex: isDragging ? 1 : 0
876
- }
877
-
878
- return (
879
- <TableCell ref={setNodeRef} className='truncate' style={style}>
880
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
881
- </TableCell>
882
- )
883
- }
884
-
885
- const DataTableWithExpandableRowsDemo = () => {
886
- const table = useReactTable({
887
- data,
888
- columns,
889
- getRowCanExpand: row => Boolean(row.original.members),
890
- getCoreRowModel: getCoreRowModel(),
891
- getExpandedRowModel: getExpandedRowModel()
892
- })
893
-
894
- return (
895
- <div className='w-full'>
896
- <div className='rounded-md border'>
897
- <Table>
898
- <TableHeader>
899
- {table.getHeaderGroups().map(headerGroup => (
900
- <TableRow key={headerGroup.id} className='hover:bg-transparent'>
901
- {headerGroup.headers.map(header => {
902
- return (
903
- <TableHead key={header.id}>
904
- {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
905
- </TableHead>
906
- )
907
- })}
908
- </TableRow>
909
- ))}
910
- </TableHeader>
911
- <TableBody>
912
- {table.getRowModel().rows?.length ? (
913
- table.getRowModel().rows.map(row => (
914
- <Fragment key={row.id}>
915
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
916
- {row.getVisibleCells().map(cell => (
917
- <TableCell
918
- key={cell.id}
919
- className='[&:has([aria-expanded])]: [&:has([aria-expanded])]:w-px [&:has([aria-expanded])]:py-0'
920
- >
921
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
922
- </TableCell>
923
- ))}
924
- </TableRow>
925
- {row.getIsExpanded() && (
926
- <TableRow className='hover:bg-transparent'>
927
- <TableCell colSpan={row.getVisibleCells().length} className='p-0'>
928
- <Table>
929
- <TableHeader className='border-b'>
930
- <TableRow className='hover:bg-muted/30!'>
931
- <TableHead className='w-23.5'></TableHead>
932
- <TableHead>Member Name</TableHead>
933
- <TableHead>Role</TableHead>
934
- <TableHead>Email</TableHead>
935
- <TableHead>Hire Date</TableHead>
936
- <TableHead>Date of Birth</TableHead>
937
- </TableRow>
938
- </TableHeader>
939
- <TableBody>
940
- {row.original.members.map(member => (
941
- <TableRow key={member.email}>
942
- <TableCell></TableCell>
943
- <TableCell>{member.name}</TableCell>
944
- <TableCell>{member.role}</TableCell>
945
- <TableCell>{member.email}</TableCell>
946
- <TableCell>{member.hireDate}</TableCell>
947
- <TableCell>{member.dob}</TableCell>
948
- </TableRow>
949
- ))}
950
- </TableBody>
951
- </Table>
952
- </TableCell>
953
- </TableRow>
954
- )}
955
- </Fragment>
956
- ))
957
- ) : (
958
- <TableRow>
959
- <TableCell colSpan={columns.length} className='h-24 text-center'>
960
- No results.
961
- </TableCell>
962
- </TableRow>
963
- )}
964
- </TableBody>
965
- </Table>
966
- </div>
967
- <p className='text-muted-foreground mt-4 text-center text-sm'>Data table with expanding sub-rows made</p>
968
- </div>
969
- )
970
- }
971
-
972
- const PaginatedDataTableDemo = () => {
973
- const id = useId()
974
-
975
- const [pagination, setPagination] = useState<PaginationState>({
976
- pageIndex: 0,
977
- pageSize: 5
978
- })
979
-
980
- const [sorting, setSorting] = useState<SortingState>([
981
- {
982
- id: 'product_name',
983
- desc: false
984
- }
985
- ])
986
-
987
- const [data, setData] = useState<Item[]>([])
988
-
989
- useEffect(() => {
990
- async function fetchPosts() {
991
- const res = await fetch('https://cdn.jsdelivr.net/gh/themeselection/fy-assets/assets/json/mobile-stock.json')
992
-
993
- if (!res.ok) {
994
- throw new Error('Failed to fetch data')
995
- }
996
-
997
- const items = await res.json()
998
-
999
- const data = await items.data
1000
-
1001
- setData([...data, ...data])
1002
- }
1003
-
1004
- fetchPosts()
1005
- }, [])
1006
-
1007
- const table = useReactTable({
1008
- data,
1009
- columns,
1010
- getCoreRowModel: getCoreRowModel(),
1011
- getSortedRowModel: getSortedRowModel(),
1012
- onSortingChange: setSorting,
1013
- enableSortingRemoval: false,
1014
- getPaginationRowModel: getPaginationRowModel(),
1015
- onPaginationChange: setPagination,
1016
- state: {
1017
- sorting,
1018
- pagination
1019
- }
1020
- })
1021
-
1022
- return (
1023
- <div className='space-y-4 md:w-full'>
1024
- <div className='rounded-md border'>
1025
- <Table>
1026
- <TableHeader>
1027
- {table.getHeaderGroups().map(headerGroup => (
1028
- <TableRow key={headerGroup.id} className='hover:bg-transparent'>
1029
- {headerGroup.headers.map(header => {
1030
- return (
1031
- <TableHead key={header.id} style={{ width: `${header.getSize()}px` }} className='h-11'>
1032
- {header.isPlaceholder ? null : header.column.getCanSort() ? (
1033
- <div
1034
- className={cn(
1035
- header.column.getCanSort() &&
1036
- 'flex h-full cursor-pointer items-center justify-between gap-2 select-none'
1037
- )}
1038
- onClick={header.column.getToggleSortingHandler()}
1039
- onKeyDown={e => {
1040
- if (header.column.getCanSort() && (e.key === 'Enter' || e.key === ' ')) {
1041
- e.preventDefault()
1042
- header.column.getToggleSortingHandler()?.(e)
1043
- }
1044
- }}
1045
- tabIndex={header.column.getCanSort() ? 0 : undefined}
1046
- >
1047
- {flexRender(header.column.columnDef.header, header.getContext())}
1048
- {{
1049
- asc: <ChevronUpIcon className='shrink-0 opacity-60' size={16} aria-hidden='true' />,
1050
- desc: <ChevronDownIcon className='shrink-0 opacity-60' size={16} aria-hidden='true' />
1051
- }[header.column.getIsSorted() as string] ?? null}
1052
- </div>
1053
- ) : (
1054
- flexRender(header.column.columnDef.header, header.getContext())
1055
- )}
1056
- </TableHead>
1057
- )
1058
- })}
1059
- </TableRow>
1060
- ))}
1061
- </TableHeader>
1062
- <TableBody>
1063
- {table.getRowModel().rows?.length ? (
1064
- table.getRowModel().rows.map(row => (
1065
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
1066
- {row.getVisibleCells().map(cell => (
1067
- <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
1068
- ))}
1069
- </TableRow>
1070
- ))
1071
- ) : (
1072
- <TableRow>
1073
- <TableCell colSpan={columns.length} className='h-24 text-center'>
1074
- No results.
1075
- </TableCell>
1076
- </TableRow>
1077
- )}
1078
- </TableBody>
1079
- </Table>
1080
- </div>
1081
-
1082
- <div className='flex items-center justify-between gap-8'>
1083
- <div className='flex items-center gap-3'>
1084
- <Label htmlFor={id} className='max-sm:sr-only'>
1085
- Rows per page
1086
- </Label>
1087
- <Select
1088
- value={table.getState().pagination.pageSize.toString()}
1089
- onValueChange={value => {
1090
- table.setPageSize(Number(value))
1091
- }}
1092
- >
1093
- <SelectTrigger id={id} className='w-fit whitespace-nowrap'>
1094
- <SelectValue placeholder='Select number of results' />
1095
- </SelectTrigger>
1096
- <SelectContent className='[&_*[role=option]]:pr-8 [&_*[role=option]]:pl-2 [&_*[role=option]>span]:right-2 [&_*[role=option]>span]:left-auto'>
1097
- {[5, 10, 25, 50].map(pageSize => (
1098
- <SelectItem key={pageSize} value={pageSize.toString()}>
1099
- {pageSize}
1100
- </SelectItem>
1101
- ))}
1102
- </SelectContent>
1103
- </Select>
1104
- </div>
1105
-
1106
- <div className='text-muted-foreground flex grow justify-end text-sm whitespace-nowrap'>
1107
- <p className='text-muted-foreground text-sm whitespace-nowrap' aria-live='polite'>
1108
- <span className='text-foreground'>
1109
- {table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}-
1110
- {Math.min(
1111
- Math.max(
1112
- table.getState().pagination.pageIndex * table.getState().pagination.pageSize +
1113
- table.getState().pagination.pageSize,
1114
- 0
1115
- ),
1116
- table.getRowCount()
1117
- )}
1118
- </span>{' '}
1119
- of <span className='text-foreground'>{table.getRowCount().toString()}</span>
1120
- </p>
1121
- </div>
1122
-
1123
- <div>
1124
- <Pagination>
1125
- <PaginationContent>
1126
- <PaginationItem>
1127
- <Button
1128
- size='icon'
1129
- variant='outline'
1130
- className='disabled:pointer-events-none disabled:opacity-50'
1131
- onClick={() => table.firstPage()}
1132
- disabled={!table.getCanPreviousPage()}
1133
- aria-label='Go to first page'
1134
- >
1135
- <ChevronFirstIcon aria-hidden='true' />
1136
- </Button>
1137
- </PaginationItem>
1138
-
1139
- <PaginationItem>
1140
- <Button
1141
- size='icon'
1142
- variant='outline'
1143
- className='disabled:pointer-events-none disabled:opacity-50'
1144
- onClick={() => table.previousPage()}
1145
- disabled={!table.getCanPreviousPage()}
1146
- aria-label='Go to previous page'
1147
- >
1148
- <ChevronLeftIcon aria-hidden='true' />
1149
- </Button>
1150
- </PaginationItem>
1151
-
1152
- <PaginationItem>
1153
- <Button
1154
- size='icon'
1155
- variant='outline'
1156
- className='disabled:pointer-events-none disabled:opacity-50'
1157
- onClick={() => table.nextPage()}
1158
- disabled={!table.getCanNextPage()}
1159
- aria-label='Go to next page'
1160
- >
1161
- <ChevronRightIcon aria-hidden='true' />
1162
- </Button>
1163
- </PaginationItem>
1164
-
1165
- <PaginationItem>
1166
- <Button
1167
- size='icon'
1168
- variant='outline'
1169
- className='disabled:pointer-events-none disabled:opacity-50'
1170
- onClick={() => table.lastPage()}
1171
- disabled={!table.getCanNextPage()}
1172
- aria-label='Go to last page'
1173
- >
1174
- <ChevronLastIcon aria-hidden='true' />
1175
- </Button>
1176
- </PaginationItem>
1177
- </PaginationContent>
1178
- </Pagination>
1179
- </div>
1180
- </div>
1181
- <p className='text-muted-foreground mt-4 text-center text-sm'>Paginated data table </p>
1182
- </div>
1183
- )
1184
- }
1185
-
1186
- const DataTableWithPaginationDemo = () => {
1187
- const pageSize = 5
1188
-
1189
- const [pagination, setPagination] = useState<PaginationState>({
1190
- pageIndex: 0,
1191
- pageSize: pageSize
1192
- })
1193
-
1194
- const [sorting, setSorting] = useState<SortingState>([
1195
- {
1196
- id: 'product_name',
1197
- desc: false
1198
- }
1199
- ])
1200
-
1201
- const [data, setData] = useState<Item[]>([])
1202
-
1203
- useEffect(() => {
1204
- async function fetchPosts() {
1205
- const res = await fetch('https://cdn.jsdelivr.net/gh/themeselection/fy-assets/assets/json/mobile-stock.json')
1206
-
1207
- if (!res.ok) {
1208
- throw new Error('Failed to fetch data')
1209
- }
1210
-
1211
- const items = await res.json()
1212
-
1213
- const data = await items.data
1214
-
1215
- setData([...data, ...data])
1216
- }
1217
-
1218
- fetchPosts()
1219
- }, [])
1220
-
1221
- const table = useReactTable({
1222
- data,
1223
- columns,
1224
- getCoreRowModel: getCoreRowModel(),
1225
- getSortedRowModel: getSortedRowModel(),
1226
- onSortingChange: setSorting,
1227
- enableSortingRemoval: false,
1228
- getPaginationRowModel: getPaginationRowModel(),
1229
- onPaginationChange: setPagination,
1230
- state: {
1231
- sorting,
1232
- pagination
1233
- }
1234
- })
1235
-
1236
- const { pages, showLeftEllipsis, showRightEllipsis } = usePagination({
1237
- currentPage: table.getState().pagination.pageIndex + 1,
1238
- totalPages: table.getPageCount(),
1239
- paginationItemsToDisplay: 5
1240
- })
1241
-
1242
- return (
1243
- <div className='w-full space-y-4'>
1244
- <div className='rounded-md border'>
1245
- <Table>
1246
- <TableHeader>
1247
- {table.getHeaderGroups().map(headerGroup => (
1248
- <TableRow key={headerGroup.id} className='hover:bg-transparent'>
1249
- {headerGroup.headers.map(header => {
1250
- return (
1251
- <TableHead key={header.id} style={{ width: `${header.getSize()}px` }} className='h-11'>
1252
- {header.isPlaceholder ? null : header.column.getCanSort() ? (
1253
- <div
1254
- className={cn(
1255
- header.column.getCanSort() &&
1256
- 'flex h-full cursor-pointer items-center justify-between gap-2 select-none'
1257
- )}
1258
- onClick={header.column.getToggleSortingHandler()}
1259
- onKeyDown={e => {
1260
- if (header.column.getCanSort() && (e.key === 'Enter' || e.key === ' ')) {
1261
- e.preventDefault()
1262
- header.column.getToggleSortingHandler()?.(e)
1263
- }
1264
- }}
1265
- tabIndex={header.column.getCanSort() ? 0 : undefined}
1266
- >
1267
- {flexRender(header.column.columnDef.header, header.getContext())}
1268
- {{
1269
- asc: <ChevronUpIcon className='shrink-0 opacity-60' size={16} aria-hidden='true' />,
1270
- desc: <ChevronDownIcon className='shrink-0 opacity-60' size={16} aria-hidden='true' />
1271
- }[header.column.getIsSorted() as string] ?? null}
1272
- </div>
1273
- ) : (
1274
- flexRender(header.column.columnDef.header, header.getContext())
1275
- )}
1276
- </TableHead>
1277
- )
1278
- })}
1279
- </TableRow>
1280
- ))}
1281
- </TableHeader>
1282
- <TableBody>
1283
- {table.getRowModel().rows?.length ? (
1284
- table.getRowModel().rows.map(row => (
1285
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
1286
- {row.getVisibleCells().map(cell => (
1287
- <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
1288
- ))}
1289
- </TableRow>
1290
- ))
1291
- ) : (
1292
- <TableRow>
1293
- <TableCell colSpan={columns.length} className='h-24 text-center'>
1294
- No results.
1295
- </TableCell>
1296
- </TableRow>
1297
- )}
1298
- </TableBody>
1299
- </Table>
1300
- </div>
1301
-
1302
- <div className='flex items-center justify-between gap-3 max-sm:flex-col'>
1303
- <p className='text-muted-foreground flex-1 text-sm whitespace-nowrap' aria-live='polite'>
1304
- Page <span className='text-foreground'>{table.getState().pagination.pageIndex + 1}</span> of{' '}
1305
- <span className='text-foreground'>{table.getPageCount()}</span>
1306
- </p>
1307
-
1308
- <div className='grow'>
1309
- <Pagination>
1310
- <PaginationContent>
1311
- <PaginationItem>
1312
- <Button
1313
- size='icon'
1314
- variant='outline'
1315
- className='disabled:pointer-events-none disabled:opacity-50'
1316
- onClick={() => table.previousPage()}
1317
- disabled={!table.getCanPreviousPage()}
1318
- aria-label='Go to previous page'
1319
- >
1320
- <ChevronLeftIcon aria-hidden='true' />
1321
- </Button>
1322
- </PaginationItem>
1323
-
1324
- {showLeftEllipsis && (
1325
- <PaginationItem>
1326
- <PaginationEllipsis />
1327
- </PaginationItem>
1328
- )}
1329
-
1330
- {pages.map(page => {
1331
- const isActive = page === table.getState().pagination.pageIndex + 1
1332
-
1333
- return (
1334
- <PaginationItem key={page}>
1335
- <Button
1336
- size='icon'
1337
- variant={`${isActive ? 'outline' : 'ghost'}`}
1338
- onClick={() => table.setPageIndex(page - 1)}
1339
- aria-current={isActive ? 'page' : undefined}
1340
- >
1341
- {page}
1342
- </Button>
1343
- </PaginationItem>
1344
- )
1345
- })}
1346
-
1347
- {showRightEllipsis && (
1348
- <PaginationItem>
1349
- <PaginationEllipsis />
1350
- </PaginationItem>
1351
- )}
1352
-
1353
- <PaginationItem>
1354
- <Button
1355
- size='icon'
1356
- variant='outline'
1357
- className='disabled:pointer-events-none disabled:opacity-50'
1358
- onClick={() => table.nextPage()}
1359
- disabled={!table.getCanNextPage()}
1360
- aria-label='Go to next page'
1361
- >
1362
- <ChevronRightIcon aria-hidden='true' />
1363
- </Button>
1364
- </PaginationItem>
1365
- </PaginationContent>
1366
- </Pagination>
1367
- </div>
1368
-
1369
- <div className='flex flex-1 justify-end'>
1370
- <Select
1371
- value={table.getState().pagination.pageSize.toString()}
1372
- onValueChange={value => {
1373
- table.setPageSize(Number(value))
1374
- }}
1375
- >
1376
- <SelectTrigger id='results-per-page' className='w-fit whitespace-nowrap' aria-label='Results per page'>
1377
- <SelectValue placeholder='Select number of results' />
1378
- </SelectTrigger>
1379
- <SelectContent>
1380
- {[5, 10, 25, 50].map(pageSize => (
1381
- <SelectItem key={pageSize} value={pageSize.toString()}>
1382
- {pageSize} / page
1383
- </SelectItem>
1384
- ))}
1385
- </SelectContent>
1386
- </Select>
1387
- </div>
1388
- </div>
1389
- <p className='text-muted-foreground mt-4 text-center text-sm'>
1390
- Data table with pagination{' '}
1391
- <a href='https://originui.com/table' className='hover:text-primary underline' target='_blank'>
1392
- Origin UI
1393
- </a>
1394
- </p>
1395
- </div>
1396
- )
1397
- }
1398
-
1399
- const DataTableWithExportDemo = () => {
1400
- const [sorting, setSorting] = useState<SortingState>([])
1401
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
1402
- const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
1403
- const [rowSelection, setRowSelection] = useState({})
1404
- const [globalFilter, setGlobalFilter] = useState('')
1405
-
1406
- const table = useReactTable({
1407
- data,
1408
- columns,
1409
- onSortingChange: setSorting,
1410
- onColumnFiltersChange: setColumnFilters,
1411
- getCoreRowModel: getCoreRowModel(),
1412
- getPaginationRowModel: getPaginationRowModel(),
1413
- getSortedRowModel: getSortedRowModel(),
1414
- getFilteredRowModel: getFilteredRowModel(),
1415
- onColumnVisibilityChange: setColumnVisibility,
1416
- onRowSelectionChange: setRowSelection,
1417
- onGlobalFilterChange: setGlobalFilter,
1418
- globalFilterFn: 'includesString',
1419
- state: {
1420
- sorting,
1421
- columnFilters,
1422
- columnVisibility,
1423
- rowSelection,
1424
- globalFilter
1425
- }
1426
- })
1427
-
1428
- const exportToCSV = () => {
1429
- const selectedRows = table.getSelectedRowModel().rows
1430
-
1431
- const dataToExport =
1432
- selectedRows.length > 0
1433
- ? selectedRows.map(row => row.original)
1434
- : table.getFilteredRowModel().rows.map(row => row.original)
1435
-
1436
- const csv = Papa.unparse(dataToExport, {
1437
- header: true
1438
- })
1439
-
1440
- const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
1441
- const link = document.createElement('a')
1442
- const url = URL.createObjectURL(blob)
1443
-
1444
- link.setAttribute('href', url)
1445
- link.setAttribute('download', `payments-export-${new Date().toISOString().split('T')[0]}.csv`)
1446
- link.style.visibility = 'hidden'
1447
- document.body.appendChild(link)
1448
- link.click()
1449
- document.body.removeChild(link)
1450
- }
1451
-
1452
- const exportToExcel = () => {
1453
- const selectedRows = table.getSelectedRowModel().rows
1454
-
1455
- const dataToExport =
1456
- selectedRows.length > 0
1457
- ? selectedRows.map(row => row.original)
1458
- : table.getFilteredRowModel().rows.map(row => row.original)
1459
-
1460
- const worksheet = XLSX.utils.json_to_sheet(dataToExport)
1461
- const workbook = XLSX.utils.book_new()
1462
-
1463
- XLSX.utils.book_append_sheet(workbook, worksheet, 'Payments')
1464
-
1465
- const cols = [{ wch: 10 }, { wch: 20 }, { wch: 15 }, { wch: 25 }, { wch: 15 }]
1466
-
1467
- worksheet['!cols'] = cols
1468
-
1469
- XLSX.writeFile(workbook, `payments-export-${new Date().toISOString().split('T')[0]}.xlsx`)
1470
- }
1471
-
1472
- const exportToJSON = () => {
1473
- const selectedRows = table.getSelectedRowModel().rows
1474
-
1475
- const dataToExport =
1476
- selectedRows.length > 0
1477
- ? selectedRows.map(row => row.original)
1478
- : table.getFilteredRowModel().rows.map(row => row.original)
1479
-
1480
- const json = JSON.stringify(dataToExport, null, 2)
1481
- const blob = new Blob([json], { type: 'application/json' })
1482
- const link = document.createElement('a')
1483
- const url = URL.createObjectURL(blob)
1484
-
1485
- link.setAttribute('href', url)
1486
- link.setAttribute('download', `payments-export-${new Date().toISOString().split('T')[0]}.json`)
1487
- link.style.visibility = 'hidden'
1488
- document.body.appendChild(link)
1489
- link.click()
1490
- document.body.removeChild(link)
1491
- }
1492
-
1493
- return (
1494
- <div className='w-full'>
1495
- <div className='flex justify-between gap-2 pb-4 max-sm:flex-col sm:items-center'>
1496
- <div className='flex items-center space-x-2'>
1497
- <Input
1498
- placeholder='Search all columns...'
1499
- value={globalFilter ?? ''}
1500
- onChange={event => setGlobalFilter(String(event.target.value))}
1501
- className='max-w-sm'
1502
- />
1503
- </div>
1504
- <div className='flex items-center space-x-2'>
1505
- <div className='text-muted-foreground text-sm'>
1506
- {table.getSelectedRowModel().rows.length > 0 && (
1507
- <span className='mr-2'>
1508
- {table.getSelectedRowModel().rows.length} of {table.getFilteredRowModel().rows.length} row(s) selected
1509
- </span>
1510
- )}
1511
- </div>
1512
- <DropdownMenu>
1513
- <DropdownMenuTrigger asChild>
1514
- <Button variant='outline' size='sm'>
1515
- <DownloadIcon className='mr-2' />
1516
- Export
1517
- </Button>
1518
- </DropdownMenuTrigger>
1519
- <DropdownMenuContent align='end'>
1520
- <DropdownMenuItem onClick={exportToCSV}>
1521
- <FileTextIcon className='mr-2 size-4' />
1522
- Export as CSV
1523
- </DropdownMenuItem>
1524
- <DropdownMenuItem onClick={exportToExcel}>
1525
- <FileSpreadsheetIcon className='mr-2 size-4' />
1526
- Export as Excel
1527
- </DropdownMenuItem>
1528
- <DropdownMenuSeparator />
1529
- <DropdownMenuItem onClick={exportToJSON}>
1530
- <FileTextIcon className='mr-2 size-4' />
1531
- Export as JSON
1532
- </DropdownMenuItem>
1533
- </DropdownMenuContent>
1534
- </DropdownMenu>
1535
- </div>
1536
- </div>
1537
- <div className='rounded-md border'>
1538
- <Table>
1539
- <TableHeader>
1540
- {table.getHeaderGroups().map(headerGroup => (
1541
- <TableRow key={headerGroup.id}>
1542
- {headerGroup.headers.map(header => {
1543
- return (
1544
- <TableHead key={header.id}>
1545
- {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
1546
- </TableHead>
1547
- )
1548
- })}
1549
- </TableRow>
1550
- ))}
1551
- </TableHeader>
1552
- <TableBody>
1553
- {table.getRowModel().rows?.length ? (
1554
- table.getRowModel().rows.map(row => (
1555
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
1556
- {row.getVisibleCells().map(cell => (
1557
- <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
1558
- ))}
1559
- </TableRow>
1560
- ))
1561
- ) : (
1562
- <TableRow>
1563
- <TableCell colSpan={columns.length} className='h-24 text-center'>
1564
- No results.
1565
- </TableCell>
1566
- </TableRow>
1567
- )}
1568
- </TableBody>
1569
- </Table>
1570
- </div>
1571
- <p className='text-muted-foreground mt-4 text-center text-sm'>
1572
- Data table with export functionality (CSV, Excel, JSON)
1573
- </p>
1574
- </div>
1575
- )
1576
- }
1577
-
1578
- const EditableTextCell = ({ getValue, row: { index }, column: { id }, table }: CellContext<Person, unknown>) => {
1579
- const initialValue = getValue() as string
1580
- const [value, setValue] = useState(initialValue)
1581
-
1582
- const onBlur = () => {
1583
- table.options.meta?.updateData(index, id, value)
1584
- }
1585
-
1586
- useEffect(() => {
1587
- setValue(initialValue)
1588
- }, [initialValue])
1589
-
1590
- return (
1591
- <Input
1592
- value={value}
1593
- onChange={e => setValue(e.target.value)}
1594
- onBlur={onBlur}
1595
- className='focus-visible:ring-ring h-8 w-full border-0 bg-transparent p-1 focus-visible:ring-1'
1596
- aria-label='editable-text-input'
1597
- />
1598
- )
1599
- }
1600
-
1601
- const EditableSelectCell = ({ getValue, row: { index }, column: { id }, table }: CellContext<Person, unknown>) => {
1602
- const initialValue = getValue() as string
1603
-
1604
- const handleValueChange = (newValue: string) => {
1605
- table.options.meta?.updateData(index, id, newValue)
1606
- }
1607
-
1608
- return (
1609
- <Select value={initialValue} onValueChange={handleValueChange}>
1610
- <SelectTrigger
1611
- className='focus:ring-ring h-8 w-full border-0 bg-transparent p-1 focus:ring-1'
1612
- aria-label={`select-status-${id}`}
1613
- >
1614
- <SelectValue />
1615
- </SelectTrigger>
1616
- <SelectContent>
1617
- <SelectItem value='active'>Active</SelectItem>
1618
- <SelectItem value='inactive'>Inactive</SelectItem>
1619
- <SelectItem value='pending'>Pending</SelectItem>
1620
- </SelectContent>
1621
- </Select>
1622
- )
1623
- }
1624
-
1625
- const EditableProgressCell = ({ getValue, row: { index }, column: { id }, table }: CellContext<Person, unknown>) => {
1626
- const initialValue = getValue() as number
1627
- const [value, setValue] = useState(initialValue.toString())
1628
-
1629
- const onBlur = () => {
1630
- const numValue = parseFloat(value)
1631
- const clampedValue = Math.max(0, Math.min(100, isNaN(numValue) ? initialValue : numValue))
1632
-
1633
- table.options.meta?.updateData(index, id, clampedValue)
1634
- }
1635
-
1636
- useEffect(() => {
1637
- setValue(initialValue.toString())
1638
- }, [initialValue])
1639
-
1640
- return (
1641
- <div className='flex items-center space-x-2'>
1642
- <Input
1643
- type='number'
1644
- min='0'
1645
- max='100'
1646
- value={value}
1647
- onChange={e => setValue(e.target.value)}
1648
- onBlur={onBlur}
1649
- className='focus-visible:ring-ring h-8 w-20 border-0 bg-transparent p-1 focus-visible:ring-1'
1650
- aria-label='editable-progress-input'
1651
- />
1652
- <span className='text-muted-foreground text-sm'>%</span>
1653
- </div>
1654
- )
1655
- }
1656
-
1657
- const EditableDataTableDemo = () => {
1658
- const [data, setData] = useState(() => [...initialData])
1659
- const [sorting, setSorting] = useState<SortingState>([])
1660
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
1661
- const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
1662
- const [rowSelection, setRowSelection] = useState({})
1663
-
1664
- const refreshData = () => setData(() => [...initialData])
1665
-
1666
- const table = useReactTable({
1667
- data,
1668
- columns,
1669
- onSortingChange: setSorting,
1670
- onColumnFiltersChange: setColumnFilters,
1671
- getCoreRowModel: getCoreRowModel(),
1672
- getSortedRowModel: getSortedRowModel(),
1673
- getFilteredRowModel: getFilteredRowModel(),
1674
- onColumnVisibilityChange: setColumnVisibility,
1675
- onRowSelectionChange: setRowSelection,
1676
- meta: {
1677
- updateData: (rowIndex, columnId, value) => {
1678
- setData(old =>
1679
- old.map((row, index) => {
1680
- if (index === rowIndex) {
1681
- return {
1682
- ...old[rowIndex]!,
1683
- [columnId]: value
1684
- }
1685
- }
1686
-
1687
- return row
1688
- })
1689
- )
1690
- }
1691
- },
1692
- state: {
1693
- sorting,
1694
- columnFilters,
1695
- columnVisibility,
1696
- rowSelection
1697
- }
1698
- })
1699
-
1700
- return (
1701
- <div className='w-full space-y-4'>
1702
- <div className='rounded-md border'>
1703
- <Table>
1704
- <TableHeader>
1705
- {table.getHeaderGroups().map(headerGroup => (
1706
- <TableRow key={headerGroup.id}>
1707
- {headerGroup.headers.map(header => {
1708
- return (
1709
- <TableHead key={header.id} colSpan={header.colSpan}>
1710
- {header.isPlaceholder ? null : (
1711
- <div>{flexRender(header.column.columnDef.header, header.getContext())}</div>
1712
- )}
1713
- </TableHead>
1714
- )
1715
- })}
1716
- </TableRow>
1717
- ))}
1718
- </TableHeader>
1719
- <TableBody>
1720
- {table.getRowModel().rows?.length ? (
1721
- table.getRowModel().rows.map(row => (
1722
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
1723
- {row.getVisibleCells().map(cell => (
1724
- <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
1725
- ))}
1726
- </TableRow>
1727
- ))
1728
- ) : (
1729
- <TableRow>
1730
- <TableCell colSpan={columns.length} className='h-24 text-center'>
1731
- No results.
1732
- </TableCell>
1733
- </TableRow>
1734
- )}
1735
- </TableBody>
1736
- </Table>
1737
- </div>
1738
-
1739
- <div className='text-muted-foreground flex items-center justify-between gap-2 text-sm max-md:flex-col'>
1740
- <div>{table.getRowModel().rows.length} rows total</div>
1741
- <div className='flex items-center space-x-2'>
1742
- <Button variant='outline' size='sm' onClick={refreshData}>
1743
- Refresh Data
1744
- </Button>
1745
- </div>
1746
- </div>
1747
-
1748
- <p className='text-muted-foreground mt-4 text-center text-sm'>
1749
- Editable data table - Click on cells to edit values
1750
- </p>
1751
- </div>
1752
- )
1753
- } */