@moontra/moonui 2.3.4 → 2.3.6
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.d.mts +14 -76
- package/dist/index.d.ts +14 -76
- package/dist/index.global.js +29 -69
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +829 -1085
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +828 -1082
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/ui/data-table-basic.tsx +261 -0
- package/src/components/ui/index.ts +4 -3
- package/src/components/ui/tabs.tsx +1 -1
- package/src/components/ui/data-table.tsx +0 -623
package/package.json
CHANGED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import {
|
|
5
|
+
ColumnDef,
|
|
6
|
+
SortingState,
|
|
7
|
+
flexRender,
|
|
8
|
+
getCoreRowModel,
|
|
9
|
+
getPaginationRowModel,
|
|
10
|
+
getSortedRowModel,
|
|
11
|
+
getFilteredRowModel,
|
|
12
|
+
useReactTable,
|
|
13
|
+
} from "@tanstack/react-table";
|
|
14
|
+
import { cn } from "../../lib/utils";
|
|
15
|
+
import { Button } from "./button";
|
|
16
|
+
import { Input } from "./input";
|
|
17
|
+
import {
|
|
18
|
+
Table,
|
|
19
|
+
TableBody,
|
|
20
|
+
TableCell,
|
|
21
|
+
TableHead,
|
|
22
|
+
TableHeader,
|
|
23
|
+
TableRow
|
|
24
|
+
} from "./table";
|
|
25
|
+
import {
|
|
26
|
+
ChevronLeft,
|
|
27
|
+
ChevronRight,
|
|
28
|
+
ArrowUpDown,
|
|
29
|
+
ArrowUp,
|
|
30
|
+
ArrowDown,
|
|
31
|
+
Search,
|
|
32
|
+
} from "lucide-react";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Basic DataTable Component
|
|
36
|
+
*
|
|
37
|
+
* A simple data table with sorting, filtering, and pagination.
|
|
38
|
+
* For advanced features, upgrade to MoonUI Pro.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
interface DataTableBasicProps<TData, TValue> {
|
|
42
|
+
/**
|
|
43
|
+
* The table columns definition
|
|
44
|
+
*/
|
|
45
|
+
columns: ColumnDef<TData, TValue>[];
|
|
46
|
+
/**
|
|
47
|
+
* The data to display
|
|
48
|
+
*/
|
|
49
|
+
data: TData[];
|
|
50
|
+
/**
|
|
51
|
+
* Enable/disable sorting
|
|
52
|
+
*/
|
|
53
|
+
enableSorting?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Enable/disable pagination
|
|
56
|
+
*/
|
|
57
|
+
enablePagination?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Enable/disable global search
|
|
60
|
+
*/
|
|
61
|
+
enableSearch?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Default page size
|
|
64
|
+
*/
|
|
65
|
+
pageSize?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Search placeholder text
|
|
68
|
+
*/
|
|
69
|
+
searchPlaceholder?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Empty state message
|
|
72
|
+
*/
|
|
73
|
+
emptyMessage?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Class name
|
|
76
|
+
*/
|
|
77
|
+
className?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function DataTableBasic<TData, TValue>({
|
|
81
|
+
columns,
|
|
82
|
+
data,
|
|
83
|
+
enableSorting = true,
|
|
84
|
+
enablePagination = true,
|
|
85
|
+
enableSearch = true,
|
|
86
|
+
pageSize = 10,
|
|
87
|
+
searchPlaceholder = "Search...",
|
|
88
|
+
emptyMessage = "No results found.",
|
|
89
|
+
className,
|
|
90
|
+
}: DataTableBasicProps<TData, TValue>) {
|
|
91
|
+
const [sorting, setSorting] = React.useState<SortingState>([]);
|
|
92
|
+
const [globalFilter, setGlobalFilter] = React.useState("");
|
|
93
|
+
|
|
94
|
+
const table = useReactTable({
|
|
95
|
+
data,
|
|
96
|
+
columns,
|
|
97
|
+
onSortingChange: enableSorting ? setSorting : undefined,
|
|
98
|
+
onGlobalFilterChange: enableSearch ? setGlobalFilter : undefined,
|
|
99
|
+
getCoreRowModel: getCoreRowModel(),
|
|
100
|
+
getPaginationRowModel: enablePagination ? getPaginationRowModel() : undefined,
|
|
101
|
+
getSortedRowModel: enableSorting ? getSortedRowModel() : undefined,
|
|
102
|
+
getFilteredRowModel: enableSearch ? getFilteredRowModel() : undefined,
|
|
103
|
+
state: {
|
|
104
|
+
sorting,
|
|
105
|
+
globalFilter,
|
|
106
|
+
},
|
|
107
|
+
initialState: {
|
|
108
|
+
pagination: {
|
|
109
|
+
pageSize,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<div className={cn("space-y-4", className)}>
|
|
116
|
+
{/* Search */}
|
|
117
|
+
{enableSearch && (
|
|
118
|
+
<div className="flex items-center">
|
|
119
|
+
<div className="relative max-w-sm">
|
|
120
|
+
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
|
|
121
|
+
<Input
|
|
122
|
+
placeholder={searchPlaceholder}
|
|
123
|
+
value={globalFilter}
|
|
124
|
+
onChange={(event) => setGlobalFilter(event.target.value)}
|
|
125
|
+
className="pl-8"
|
|
126
|
+
/>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
)}
|
|
130
|
+
|
|
131
|
+
{/* Table */}
|
|
132
|
+
<div className="rounded-md border">
|
|
133
|
+
<Table>
|
|
134
|
+
<TableHeader>
|
|
135
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
136
|
+
<TableRow key={headerGroup.id}>
|
|
137
|
+
{headerGroup.headers.map((header) => {
|
|
138
|
+
return (
|
|
139
|
+
<TableHead key={header.id}>
|
|
140
|
+
{header.isPlaceholder ? null : (
|
|
141
|
+
<div
|
|
142
|
+
className={cn(
|
|
143
|
+
"flex items-center gap-2",
|
|
144
|
+
header.column.getCanSort() && "cursor-pointer select-none"
|
|
145
|
+
)}
|
|
146
|
+
onClick={header.column.getToggleSortingHandler()}
|
|
147
|
+
>
|
|
148
|
+
{flexRender(
|
|
149
|
+
header.column.columnDef.header,
|
|
150
|
+
header.getContext()
|
|
151
|
+
)}
|
|
152
|
+
{enableSorting && header.column.getCanSort() && (
|
|
153
|
+
<div className="ml-auto">
|
|
154
|
+
{header.column.getIsSorted() === "desc" ? (
|
|
155
|
+
<ArrowDown className="h-4 w-4" />
|
|
156
|
+
) : header.column.getIsSorted() === "asc" ? (
|
|
157
|
+
<ArrowUp className="h-4 w-4" />
|
|
158
|
+
) : (
|
|
159
|
+
<ArrowUpDown className="h-4 w-4 opacity-50" />
|
|
160
|
+
)}
|
|
161
|
+
</div>
|
|
162
|
+
)}
|
|
163
|
+
</div>
|
|
164
|
+
)}
|
|
165
|
+
</TableHead>
|
|
166
|
+
);
|
|
167
|
+
})}
|
|
168
|
+
</TableRow>
|
|
169
|
+
))}
|
|
170
|
+
</TableHeader>
|
|
171
|
+
<TableBody>
|
|
172
|
+
{table.getRowModel().rows?.length ? (
|
|
173
|
+
table.getRowModel().rows.map((row) => (
|
|
174
|
+
<TableRow
|
|
175
|
+
key={row.id}
|
|
176
|
+
data-state={row.getIsSelected() && "selected"}
|
|
177
|
+
>
|
|
178
|
+
{row.getVisibleCells().map((cell) => (
|
|
179
|
+
<TableCell key={cell.id}>
|
|
180
|
+
{flexRender(
|
|
181
|
+
cell.column.columnDef.cell,
|
|
182
|
+
cell.getContext()
|
|
183
|
+
)}
|
|
184
|
+
</TableCell>
|
|
185
|
+
))}
|
|
186
|
+
</TableRow>
|
|
187
|
+
))
|
|
188
|
+
) : (
|
|
189
|
+
<TableRow>
|
|
190
|
+
<TableCell
|
|
191
|
+
colSpan={columns.length}
|
|
192
|
+
className="h-24 text-center"
|
|
193
|
+
>
|
|
194
|
+
{emptyMessage}
|
|
195
|
+
</TableCell>
|
|
196
|
+
</TableRow>
|
|
197
|
+
)}
|
|
198
|
+
</TableBody>
|
|
199
|
+
</Table>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
{/* Pagination */}
|
|
203
|
+
{enablePagination && (
|
|
204
|
+
<div className="flex items-center justify-end space-x-2">
|
|
205
|
+
<div className="flex-1 text-sm text-muted-foreground">
|
|
206
|
+
{table.getFilteredRowModel().rows.length} row(s)
|
|
207
|
+
</div>
|
|
208
|
+
<div className="space-x-2">
|
|
209
|
+
<Button
|
|
210
|
+
variant="outline"
|
|
211
|
+
size="sm"
|
|
212
|
+
onClick={() => table.previousPage()}
|
|
213
|
+
disabled={!table.getCanPreviousPage()}
|
|
214
|
+
>
|
|
215
|
+
<ChevronLeft className="h-4 w-4" />
|
|
216
|
+
Previous
|
|
217
|
+
</Button>
|
|
218
|
+
<span className="text-sm">
|
|
219
|
+
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
|
220
|
+
{table.getPageCount()}
|
|
221
|
+
</span>
|
|
222
|
+
<Button
|
|
223
|
+
variant="outline"
|
|
224
|
+
size="sm"
|
|
225
|
+
onClick={() => table.nextPage()}
|
|
226
|
+
disabled={!table.getCanNextPage()}
|
|
227
|
+
>
|
|
228
|
+
Next
|
|
229
|
+
<ChevronRight className="h-4 w-4" />
|
|
230
|
+
</Button>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
)}
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Simple sortable header helper
|
|
240
|
+
*/
|
|
241
|
+
export function createSortableHeader(label: string) {
|
|
242
|
+
return ({ column }: any) => (
|
|
243
|
+
<Button
|
|
244
|
+
variant="ghost"
|
|
245
|
+
className="-ml-3 h-8 data-[state=open]:bg-accent"
|
|
246
|
+
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
|
247
|
+
>
|
|
248
|
+
{label}
|
|
249
|
+
{column.getIsSorted() === "desc" ? (
|
|
250
|
+
<ArrowDown className="ml-2 h-4 w-4" />
|
|
251
|
+
) : column.getIsSorted() === "asc" ? (
|
|
252
|
+
<ArrowUp className="ml-2 h-4 w-4" />
|
|
253
|
+
) : (
|
|
254
|
+
<ArrowUpDown className="ml-2 h-4 w-4" />
|
|
255
|
+
)}
|
|
256
|
+
</Button>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Export utilities
|
|
261
|
+
export { type ColumnDef } from "@tanstack/react-table";
|
|
@@ -104,8 +104,10 @@ export {
|
|
|
104
104
|
CommandSeparator as MoonUICommandSeparator,
|
|
105
105
|
} from "./command";
|
|
106
106
|
|
|
107
|
-
// DataTable
|
|
108
|
-
export {
|
|
107
|
+
// DataTable Basic (Free version with limited features)
|
|
108
|
+
export { DataTableBasic as MoonUIDataTableBasic } from "./data-table-basic";
|
|
109
|
+
export { createSortableHeader as moonUICreateSortableHeader } from "./data-table-basic";
|
|
110
|
+
export type { ColumnDef as MoonUIColumnDef } from "./data-table-basic";
|
|
109
111
|
|
|
110
112
|
// DatePicker
|
|
111
113
|
export {
|
|
@@ -322,7 +324,6 @@ export * from "./checkbox";
|
|
|
322
324
|
export * from "./collapsible";
|
|
323
325
|
export * from "./color-picker";
|
|
324
326
|
export * from "./command";
|
|
325
|
-
export * from "./data-table";
|
|
326
327
|
export * from "./date-picker";
|
|
327
328
|
export * from "./dialog";
|
|
328
329
|
export * from "./draggable-list";
|
|
@@ -187,7 +187,7 @@ const TabsContent = React.forwardRef<
|
|
|
187
187
|
ref={ref}
|
|
188
188
|
className={cn(
|
|
189
189
|
"moonui-theme",
|
|
190
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
190
|
+
"mt-6 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
191
191
|
animated && "data-[state=active]:animate-fadeIn data-[state=inactive]:animate-fadeOut",
|
|
192
192
|
className
|
|
193
193
|
)}
|