@mdaushi/kinetics-react 0.1.0-a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,780 @@
1
+ import { router } from '@inertiajs/react';
2
+ import { useReactTable, getCoreRowModel, flexRender } from '@tanstack/react-table';
3
+ import React, { useMemo, useState, useCallback } from 'react';
4
+ import { useDebouncedCallback } from 'use-debounce';
5
+ import { TableController, formatValue } from '@mdaushi/kinetics-core';
6
+ import { clsx } from 'clsx';
7
+ import { twMerge } from 'tailwind-merge';
8
+ import { Button as Button$1 } from '@base-ui/react/button';
9
+ import { cva } from 'class-variance-authority';
10
+ import { jsx, jsxs } from 'react/jsx-runtime';
11
+ import { Menu } from '@base-ui/react/menu';
12
+ import { ArrowDown, ArrowUp, ChevronsUpDown, X, ChevronsLeft, ChevronLeft, ChevronRight, ChevronsRight, ChevronDownIcon, CheckIcon, ChevronUpIcon } from 'lucide-react';
13
+ import { DynamicIcon } from 'lucide-react/dynamic';
14
+ import { Select as Select$1 } from '@base-ui/react/select';
15
+ import { Input as Input$1 } from '@base-ui/react/input';
16
+
17
+ // src/hooks/use-table.ts
18
+ function cn(...inputs) {
19
+ return twMerge(clsx(inputs));
20
+ }
21
+ var buttonVariants = cva(
22
+ "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
23
+ {
24
+ variants: {
25
+ variant: {
26
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
27
+ outline: "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
28
+ secondary: "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
29
+ ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
30
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
31
+ link: "text-primary underline-offset-4 hover:underline"
32
+ },
33
+ size: {
34
+ default: "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
35
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
36
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
37
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
38
+ icon: "size-8",
39
+ "icon-xs": "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
40
+ "icon-sm": "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
41
+ "icon-lg": "size-9"
42
+ }
43
+ },
44
+ defaultVariants: {
45
+ variant: "default",
46
+ size: "default"
47
+ }
48
+ }
49
+ );
50
+ function Button({
51
+ className,
52
+ variant = "default",
53
+ size = "default",
54
+ ...props
55
+ }) {
56
+ return /* @__PURE__ */ jsx(
57
+ Button$1,
58
+ {
59
+ "data-slot": "button",
60
+ className: cn(buttonVariants({ variant, size, className })),
61
+ ...props
62
+ }
63
+ );
64
+ }
65
+ function DropdownMenu({ ...props }) {
66
+ return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
67
+ }
68
+ function DropdownMenuTrigger({ ...props }) {
69
+ return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
70
+ }
71
+ function DropdownMenuContent({
72
+ align = "start",
73
+ alignOffset = 0,
74
+ side = "bottom",
75
+ sideOffset = 4,
76
+ className,
77
+ ...props
78
+ }) {
79
+ return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
80
+ Menu.Positioner,
81
+ {
82
+ className: "isolate z-50 outline-none",
83
+ align,
84
+ alignOffset,
85
+ side,
86
+ sideOffset,
87
+ children: /* @__PURE__ */ jsx(
88
+ Menu.Popup,
89
+ {
90
+ "data-slot": "dropdown-menu-content",
91
+ className: cn(
92
+ "z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95",
93
+ className
94
+ ),
95
+ ...props
96
+ }
97
+ )
98
+ }
99
+ ) });
100
+ }
101
+ function DropdownMenuItem({
102
+ className,
103
+ inset,
104
+ variant = "default",
105
+ ...props
106
+ }) {
107
+ return /* @__PURE__ */ jsx(
108
+ Menu.Item,
109
+ {
110
+ "data-slot": "dropdown-menu-item",
111
+ "data-inset": inset,
112
+ "data-variant": variant,
113
+ className: cn(
114
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
115
+ className
116
+ ),
117
+ ...props
118
+ }
119
+ );
120
+ }
121
+ function ActionCell({ actions }) {
122
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-1", children: actions.map(
123
+ (item, idx) => item.type === "group" ? /* @__PURE__ */ jsx(ActionGroupDropdown, { group: item }, idx) : /* @__PURE__ */ jsx(ActionButton, { action: item }, item.key)
124
+ ) });
125
+ }
126
+ function ActionButton({ action }) {
127
+ function handleClick() {
128
+ if (action.disabled) return;
129
+ execute(action);
130
+ }
131
+ return /* @__PURE__ */ jsxs(
132
+ Button,
133
+ {
134
+ size: "sm",
135
+ onClick: handleClick,
136
+ disabled: action.disabled,
137
+ title: action.label,
138
+ variant: action.variant,
139
+ children: [
140
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon }),
141
+ /* @__PURE__ */ jsx("span", { className: "sr-only sm:not-sr-only", children: action.label })
142
+ ]
143
+ }
144
+ );
145
+ }
146
+ function ActionGroupDropdown({ group }) {
147
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
148
+ /* @__PURE__ */ jsx(
149
+ DropdownMenuTrigger,
150
+ {
151
+ render: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "icon", children: [
152
+ group.icon && /* @__PURE__ */ jsx(Icon, { name: group.icon }),
153
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Open menu" })
154
+ ] })
155
+ }
156
+ ),
157
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", className: "w-40", children: group.actions.map((action) => /* @__PURE__ */ jsxs(
158
+ DropdownMenuItem,
159
+ {
160
+ disabled: action.disabled,
161
+ variant: action.variant,
162
+ children: [
163
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon }),
164
+ action.label
165
+ ]
166
+ },
167
+ action.key
168
+ )) })
169
+ ] });
170
+ }
171
+ function execute(action) {
172
+ if (!action.href) return;
173
+ if (action.method === "get") {
174
+ router.visit(action.href);
175
+ } else {
176
+ router.visit(action.href, { method: action.method });
177
+ }
178
+ }
179
+ function Icon({ name, size = 16 }) {
180
+ return /* @__PURE__ */ jsx(DynamicIcon, { name, size });
181
+ }
182
+ function TableColumnHeader({
183
+ column,
184
+ title,
185
+ className
186
+ }) {
187
+ if (!column.getCanSort()) {
188
+ return /* @__PURE__ */ jsx("div", { className: cn(className), children: title });
189
+ }
190
+ return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-2", className), children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
191
+ /* @__PURE__ */ jsx(
192
+ DropdownMenuTrigger,
193
+ {
194
+ render: /* @__PURE__ */ jsxs(
195
+ Button,
196
+ {
197
+ variant: "ghost",
198
+ size: "sm",
199
+ className: "-ml-3 h-8 data-[state=open]:bg-accent",
200
+ children: [
201
+ /* @__PURE__ */ jsx("span", { children: title }),
202
+ column.getIsSorted() === "desc" ? /* @__PURE__ */ jsx(ArrowDown, {}) : column.getIsSorted() === "asc" ? /* @__PURE__ */ jsx(ArrowUp, {}) : /* @__PURE__ */ jsx(ChevronsUpDown, {})
203
+ ]
204
+ }
205
+ )
206
+ }
207
+ ),
208
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", children: [
209
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => column.toggleSorting(false), children: [
210
+ /* @__PURE__ */ jsx(ArrowUp, {}),
211
+ "Asc"
212
+ ] }),
213
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => column.toggleSorting(true), children: [
214
+ /* @__PURE__ */ jsx(ArrowDown, {}),
215
+ "Desc"
216
+ ] })
217
+ ] })
218
+ ] }) });
219
+ }
220
+
221
+ // src/hooks/use-table.ts
222
+ function useTable({
223
+ table: serverData,
224
+ url,
225
+ searchDebounce = 300
226
+ }) {
227
+ const { data, columns: serverColumns, meta, state: serverState } = serverData;
228
+ const ctrl = useMemo(
229
+ () => new TableController(serverState, meta),
230
+ [serverState, meta, url]
231
+ );
232
+ const [search, setSearchLocal] = useState(serverState.search ?? "");
233
+ const visit = useCallback(
234
+ (params) => {
235
+ router.get(url ?? window.location.pathname, params, {
236
+ preserveState: true,
237
+ preserveScroll: true,
238
+ replace: true
239
+ });
240
+ },
241
+ [url]
242
+ );
243
+ const handleSortChange = useCallback(
244
+ (updater) => {
245
+ const current = ctrl.toSorting();
246
+ const next = typeof updater === "function" ? updater(current) : updater;
247
+ visit(ctrl.resolveSort(next));
248
+ },
249
+ [ctrl, visit]
250
+ );
251
+ const handlePageChange = useCallback(
252
+ (updater) => {
253
+ const current = ctrl.toPagination();
254
+ const next = typeof updater === "function" ? updater(current) : updater;
255
+ visit(ctrl.resolvePagination(next));
256
+ },
257
+ [ctrl, visit]
258
+ );
259
+ const handleSearchChange = useDebouncedCallback((value) => {
260
+ visit(ctrl.resolveSearchParams(value));
261
+ }, searchDebounce);
262
+ const handleFilterChange = useCallback(
263
+ (key, value) => {
264
+ visit(ctrl.resolveFilterParams(key, value));
265
+ },
266
+ [ctrl, visit]
267
+ );
268
+ const columnDefs = useMemo(() => {
269
+ return serverColumns.filter((col) => col.visible).map((col) => {
270
+ if (col.type === "actions") {
271
+ return {
272
+ id: col.key,
273
+ accessorKey: col.key,
274
+ header: col.label,
275
+ enableSorting: false,
276
+ cell: ({ getValue }) => React.createElement(ActionCell, {
277
+ actions: getValue() ?? []
278
+ })
279
+ };
280
+ }
281
+ return {
282
+ id: col.key,
283
+ accessorKey: col.key,
284
+ header: ({ column }) => React.createElement(TableColumnHeader, {
285
+ column,
286
+ title: col.label
287
+ }),
288
+ enableSorting: col.sortable,
289
+ enableColumnFilter: col.filterable,
290
+ cell: ({ getValue }) => {
291
+ const value = getValue();
292
+ return formatValue(value, col.type);
293
+ }
294
+ };
295
+ });
296
+ }, [serverColumns]);
297
+ const tableInstance = useReactTable({
298
+ data,
299
+ columns: columnDefs,
300
+ state: {
301
+ sorting: ctrl.toSorting(),
302
+ pagination: ctrl.toPagination()
303
+ },
304
+ manualSorting: true,
305
+ manualPagination: true,
306
+ manualFiltering: true,
307
+ pageCount: meta.last_page,
308
+ onSortingChange: handleSortChange,
309
+ onPaginationChange: handlePageChange,
310
+ getCoreRowModel: getCoreRowModel()
311
+ });
312
+ return {
313
+ tableInstance,
314
+ columns: serverColumns,
315
+ meta,
316
+ search,
317
+ setSearch: (value) => {
318
+ setSearchLocal(value);
319
+ handleSearchChange(value);
320
+ },
321
+ setFilter: handleFilterChange,
322
+ filters: serverState.filters
323
+ };
324
+ }
325
+ function Label({ className, ...props }) {
326
+ return /* @__PURE__ */ jsx(
327
+ "label",
328
+ {
329
+ "data-slot": "label",
330
+ className: cn(
331
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
332
+ className
333
+ ),
334
+ ...props
335
+ }
336
+ );
337
+ }
338
+ var Select = Select$1.Root;
339
+ function SelectGroup({ className, ...props }) {
340
+ return /* @__PURE__ */ jsx(
341
+ Select$1.Group,
342
+ {
343
+ "data-slot": "select-group",
344
+ className: cn("scroll-my-1 p-1", className),
345
+ ...props
346
+ }
347
+ );
348
+ }
349
+ function SelectValue({ className, ...props }) {
350
+ return /* @__PURE__ */ jsx(
351
+ Select$1.Value,
352
+ {
353
+ "data-slot": "select-value",
354
+ className: cn("flex flex-1 text-left", className),
355
+ ...props
356
+ }
357
+ );
358
+ }
359
+ function SelectTrigger({
360
+ className,
361
+ size = "default",
362
+ children,
363
+ ...props
364
+ }) {
365
+ return /* @__PURE__ */ jsxs(
366
+ Select$1.Trigger,
367
+ {
368
+ "data-slot": "select-trigger",
369
+ "data-size": size,
370
+ className: cn(
371
+ "flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
372
+ className
373
+ ),
374
+ ...props,
375
+ children: [
376
+ children,
377
+ /* @__PURE__ */ jsx(
378
+ Select$1.Icon,
379
+ {
380
+ render: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "pointer-events-none size-4 text-muted-foreground" })
381
+ }
382
+ )
383
+ ]
384
+ }
385
+ );
386
+ }
387
+ function SelectContent({
388
+ className,
389
+ children,
390
+ side = "bottom",
391
+ sideOffset = 4,
392
+ align = "center",
393
+ alignOffset = 0,
394
+ alignItemWithTrigger = true,
395
+ ...props
396
+ }) {
397
+ return /* @__PURE__ */ jsx(Select$1.Portal, { children: /* @__PURE__ */ jsx(
398
+ Select$1.Positioner,
399
+ {
400
+ side,
401
+ sideOffset,
402
+ align,
403
+ alignOffset,
404
+ alignItemWithTrigger,
405
+ className: "isolate z-50",
406
+ children: /* @__PURE__ */ jsxs(
407
+ Select$1.Popup,
408
+ {
409
+ "data-slot": "select-content",
410
+ "data-align-trigger": alignItemWithTrigger,
411
+ className: cn(
412
+ "relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
413
+ className
414
+ ),
415
+ ...props,
416
+ children: [
417
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
418
+ /* @__PURE__ */ jsx(Select$1.List, { children }),
419
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
420
+ ]
421
+ }
422
+ )
423
+ }
424
+ ) });
425
+ }
426
+ function SelectItem({
427
+ className,
428
+ children,
429
+ ...props
430
+ }) {
431
+ return /* @__PURE__ */ jsxs(
432
+ Select$1.Item,
433
+ {
434
+ "data-slot": "select-item",
435
+ className: cn(
436
+ "relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
437
+ className
438
+ ),
439
+ ...props,
440
+ children: [
441
+ /* @__PURE__ */ jsx(Select$1.ItemText, { className: "flex flex-1 shrink-0 gap-2 whitespace-nowrap", children }),
442
+ /* @__PURE__ */ jsx(
443
+ Select$1.ItemIndicator,
444
+ {
445
+ render: /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center", children: /* @__PURE__ */ jsx(CheckIcon, { className: "pointer-events-none" }) })
446
+ }
447
+ )
448
+ ]
449
+ }
450
+ );
451
+ }
452
+ function SelectScrollUpButton({
453
+ className,
454
+ ...props
455
+ }) {
456
+ return /* @__PURE__ */ jsx(
457
+ Select$1.ScrollUpArrow,
458
+ {
459
+ "data-slot": "select-scroll-up-button",
460
+ className: cn(
461
+ "top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
462
+ className
463
+ ),
464
+ ...props,
465
+ children: /* @__PURE__ */ jsx(ChevronUpIcon, {})
466
+ }
467
+ );
468
+ }
469
+ function SelectScrollDownButton({
470
+ className,
471
+ ...props
472
+ }) {
473
+ return /* @__PURE__ */ jsx(
474
+ Select$1.ScrollDownArrow,
475
+ {
476
+ "data-slot": "select-scroll-down-button",
477
+ className: cn(
478
+ "bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
479
+ className
480
+ ),
481
+ ...props,
482
+ children: /* @__PURE__ */ jsx(ChevronDownIcon, {})
483
+ }
484
+ );
485
+ }
486
+ function TablePagination({
487
+ meta,
488
+ table
489
+ }) {
490
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
491
+ /* @__PURE__ */ jsx("div", { className: "flex-1 text-sm text-muted-foreground", children: /* @__PURE__ */ jsxs("span", { children: [
492
+ "Showing ",
493
+ /* @__PURE__ */ jsx("strong", { children: meta.from ?? 0 }),
494
+ "-",
495
+ /* @__PURE__ */ jsxs("strong", { children: [
496
+ " ",
497
+ meta.to ?? 0
498
+ ] }),
499
+ " of ",
500
+ /* @__PURE__ */ jsx("strong", { children: meta.total }),
501
+ " ",
502
+ "results"
503
+ ] }) }),
504
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-6 lg:space-x-8", children: [
505
+ /* @__PURE__ */ jsxs("div", { className: "hidden items-center gap-2 lg:flex", children: [
506
+ /* @__PURE__ */ jsx(Label, { htmlFor: "rows-per-page", className: "text-sm font-medium", children: "Rows per page" }),
507
+ /* @__PURE__ */ jsxs(
508
+ Select,
509
+ {
510
+ value: meta.per_page.toString(),
511
+ onValueChange: (value) => table.setPageSize(Number(value)),
512
+ children: [
513
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "w-20", id: "rows-per-page", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: meta.per_page }) }),
514
+ /* @__PURE__ */ jsx(SelectContent, { side: "left", align: "end", children: [10, 15, 50, 100].map((pageSize) => /* @__PURE__ */ jsx(SelectItem, { value: `${pageSize}`, children: pageSize }, pageSize)) })
515
+ ]
516
+ }
517
+ )
518
+ ] }),
519
+ /* @__PURE__ */ jsxs("div", { className: "flex w-fit items-center justify-center text-sm font-medium", children: [
520
+ "Page ",
521
+ meta.current_page,
522
+ " of ",
523
+ meta.last_page
524
+ ] }),
525
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2 lg:ml-0", children: [
526
+ /* @__PURE__ */ jsxs(
527
+ Button,
528
+ {
529
+ variant: "outline",
530
+ className: "hidden h-8 w-8 p-0 lg:flex",
531
+ onClick: () => table.firstPage(),
532
+ disabled: !table.getCanPreviousPage(),
533
+ children: [
534
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Go to first page" }),
535
+ /* @__PURE__ */ jsx(ChevronsLeft, {})
536
+ ]
537
+ }
538
+ ),
539
+ /* @__PURE__ */ jsxs(
540
+ Button,
541
+ {
542
+ variant: "outline",
543
+ className: "size-8",
544
+ size: "icon",
545
+ onClick: () => table.previousPage(),
546
+ disabled: !table.getCanPreviousPage(),
547
+ children: [
548
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Go to previous page" }),
549
+ /* @__PURE__ */ jsx(ChevronLeft, {})
550
+ ]
551
+ }
552
+ ),
553
+ /* @__PURE__ */ jsxs(
554
+ Button,
555
+ {
556
+ variant: "outline",
557
+ className: "size-8",
558
+ size: "icon",
559
+ onClick: () => table.nextPage(),
560
+ disabled: !table.getCanNextPage(),
561
+ children: [
562
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Go to next page" }),
563
+ /* @__PURE__ */ jsx(ChevronRight, {})
564
+ ]
565
+ }
566
+ ),
567
+ /* @__PURE__ */ jsxs(
568
+ Button,
569
+ {
570
+ variant: "outline",
571
+ className: "hidden size-8 lg:flex",
572
+ size: "icon",
573
+ onClick: () => table.lastPage(),
574
+ disabled: !table.getCanNextPage(),
575
+ children: [
576
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Go to last page" }),
577
+ /* @__PURE__ */ jsx(ChevronsRight, {})
578
+ ]
579
+ }
580
+ )
581
+ ] })
582
+ ] })
583
+ ] });
584
+ }
585
+ function Input({ className, type, ...props }) {
586
+ return /* @__PURE__ */ jsx(
587
+ Input$1,
588
+ {
589
+ type,
590
+ "data-slot": "input",
591
+ className: cn(
592
+ "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
593
+ className
594
+ ),
595
+ ...props
596
+ }
597
+ );
598
+ }
599
+ function TableToolbar({
600
+ search,
601
+ columns,
602
+ setSearch,
603
+ placeholder,
604
+ filters,
605
+ setFilter
606
+ }) {
607
+ const filterableColumns = columns.filter((c) => c.filterable);
608
+ const hasSearch = columns.some((c) => c.searchable);
609
+ const hasFilter = search || Object.keys(filters).length > 0;
610
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-2", children: [
611
+ hasSearch && /* @__PURE__ */ jsx(
612
+ Input,
613
+ {
614
+ placeholder,
615
+ value: search,
616
+ onChange: (e) => setSearch(e.target.value),
617
+ className: "h-8 w-37.5 lg:w-62.5"
618
+ }
619
+ ),
620
+ filterableColumns.map((col) => {
621
+ const options = Array.isArray(col.filterOptions) ? Object.fromEntries(col.filterOptions.map((o) => [o, o])) : col.filterOptions;
622
+ return /* @__PURE__ */ jsxs(
623
+ Select,
624
+ {
625
+ items: options,
626
+ value: filters[col.key] ?? "",
627
+ onValueChange: (e) => setFilter(col.key, e || null),
628
+ children: [
629
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: col.label }) }),
630
+ /* @__PURE__ */ jsx(SelectContent, { children: /* @__PURE__ */ jsxs(SelectGroup, { children: [
631
+ /* @__PURE__ */ jsxs(SelectItem, { value: "", children: [
632
+ "All ",
633
+ col.label
634
+ ] }),
635
+ Object.entries(options).map(([value, label]) => /* @__PURE__ */ jsx(SelectItem, { value, children: label }, value))
636
+ ] }) })
637
+ ]
638
+ }
639
+ );
640
+ }),
641
+ hasFilter && /* @__PURE__ */ jsxs(Button, { variant: "ghost", children: [
642
+ "Reset",
643
+ /* @__PURE__ */ jsx(X, {})
644
+ ] })
645
+ ] }) });
646
+ }
647
+ function Table({ className, ...props }) {
648
+ return /* @__PURE__ */ jsx(
649
+ "div",
650
+ {
651
+ "data-slot": "table-container",
652
+ className: "relative w-full overflow-x-auto",
653
+ children: /* @__PURE__ */ jsx(
654
+ "table",
655
+ {
656
+ "data-slot": "table",
657
+ className: cn("w-full caption-bottom text-sm", className),
658
+ ...props
659
+ }
660
+ )
661
+ }
662
+ );
663
+ }
664
+ function TableHeader({ className, ...props }) {
665
+ return /* @__PURE__ */ jsx(
666
+ "thead",
667
+ {
668
+ "data-slot": "table-header",
669
+ className: cn("[&_tr]:border-b", className),
670
+ ...props
671
+ }
672
+ );
673
+ }
674
+ function TableBody({ className, ...props }) {
675
+ return /* @__PURE__ */ jsx(
676
+ "tbody",
677
+ {
678
+ "data-slot": "table-body",
679
+ className: cn("[&_tr:last-child]:border-0", className),
680
+ ...props
681
+ }
682
+ );
683
+ }
684
+ function TableRow({ className, ...props }) {
685
+ return /* @__PURE__ */ jsx(
686
+ "tr",
687
+ {
688
+ "data-slot": "table-row",
689
+ className: cn(
690
+ "border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted",
691
+ className
692
+ ),
693
+ ...props
694
+ }
695
+ );
696
+ }
697
+ function TableHead({ className, ...props }) {
698
+ return /* @__PURE__ */ jsx(
699
+ "th",
700
+ {
701
+ "data-slot": "table-head",
702
+ className: cn(
703
+ "h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
704
+ className
705
+ ),
706
+ ...props
707
+ }
708
+ );
709
+ }
710
+ function TableCell({ className, ...props }) {
711
+ return /* @__PURE__ */ jsx(
712
+ "td",
713
+ {
714
+ "data-slot": "table-cell",
715
+ className: cn(
716
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
717
+ className
718
+ ),
719
+ ...props
720
+ }
721
+ );
722
+ }
723
+ function RenderTable({ table }) {
724
+ return /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
725
+ /* @__PURE__ */ jsx(TableHeader, { className: "sticky top-0 z-10 bg-muted", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => {
726
+ return /* @__PURE__ */ jsx(TableHead, { colSpan: header.colSpan, children: header.isPlaceholder ? null : flexRender(
727
+ header.column.columnDef.header,
728
+ header.getContext()
729
+ ) }, header.id);
730
+ }) }, headerGroup.id)) }),
731
+ /* @__PURE__ */ jsx(TableBody, { children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx(
732
+ TableRow,
733
+ {
734
+ "data-state": row.getIsSelected() && "selected",
735
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))
736
+ },
737
+ row.id
738
+ )) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(
739
+ TableCell,
740
+ {
741
+ colSpan: table.getAllColumns.length,
742
+ className: "h-24 text-center",
743
+ children: "No results."
744
+ }
745
+ ) }) })
746
+ ] }) });
747
+ }
748
+ function Table2({
749
+ table: serverData,
750
+ searchPlaceholder = "Search..."
751
+ }) {
752
+ const {
753
+ tableInstance,
754
+ columns: serverColumns,
755
+ meta,
756
+ search,
757
+ setSearch,
758
+ setFilter,
759
+ filters
760
+ } = useTable({ table: serverData });
761
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
762
+ /* @__PURE__ */ jsx(
763
+ TableToolbar,
764
+ {
765
+ search,
766
+ setSearch,
767
+ placeholder: searchPlaceholder,
768
+ columns: serverColumns,
769
+ filters,
770
+ setFilter
771
+ }
772
+ ),
773
+ /* @__PURE__ */ jsx(RenderTable, { table: tableInstance }),
774
+ /* @__PURE__ */ jsx(TablePagination, { meta, table: tableInstance })
775
+ ] });
776
+ }
777
+
778
+ export { ActionCell, Table2 as Table, useTable };
779
+ //# sourceMappingURL=index.js.map
780
+ //# sourceMappingURL=index.js.map