@caffeinebounce/ui 0.62.2 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +1 -1
  2. package/dist/blog.js +8 -6
  3. package/dist/blog.mjs +3 -1
  4. package/dist/charts.d.cts +1 -1
  5. package/dist/charts.d.ts +1 -1
  6. package/dist/{chunk-6DVWMJ3H.mjs → chunk-2EFVMX6V.mjs} +4 -3
  7. package/dist/chunk-33JR5SYE.js +1 -0
  8. package/dist/{chunk-OZZWDIOY.js → chunk-375DECW4.js} +32 -31
  9. package/dist/chunk-3NDB4YPC.js +1 -0
  10. package/dist/{chunk-PZRI43EZ.js → chunk-46JYKBRX.js} +0 -43
  11. package/dist/chunk-5D55OVD5.js +75 -0
  12. package/dist/chunk-5RW4PYZ6.js +1 -0
  13. package/dist/chunk-5THF4YP6.mjs +1 -0
  14. package/dist/{chunk-JORVSG52.js → chunk-663CFAHS.js} +212 -269
  15. package/dist/chunk-6BUBNZPG.mjs +1 -0
  16. package/dist/chunk-6HKJDV43.mjs +48 -0
  17. package/dist/chunk-6NCRGHV3.mjs +64 -0
  18. package/dist/{chunk-OLAAXLXY.mjs → chunk-6QAKQG57.mjs} +5 -4
  19. package/dist/chunk-72JGQ7IJ.mjs +1 -0
  20. package/dist/{chunk-N6AFNFZR.mjs → chunk-7ERVZXIN.mjs} +215 -270
  21. package/dist/chunk-7IKHZKAC.js +1 -0
  22. package/dist/chunk-APFEP5B7.mjs +100 -0
  23. package/dist/chunk-C3OADNSG.js +348 -0
  24. package/dist/{chunk-RVEFPVZF.mjs → chunk-C57MX3BG.mjs} +1 -0
  25. package/dist/{chunk-CC4KUIKC.js → chunk-DH5Z3ETN.js} +67 -45
  26. package/dist/chunk-DYWZ23QT.mjs +90 -0
  27. package/dist/{chunk-KRRIRS6A.mjs → chunk-E67IR6HU.mjs} +31 -9
  28. package/dist/{chunk-D3QXPL47.mjs → chunk-EXQSWHLD.mjs} +7 -6
  29. package/dist/{chunk-ZOA7B32D.js → chunk-F35KL6TX.js} +10 -9
  30. package/dist/{chunk-YSLD2HLP.mjs → chunk-FFJC66KO.mjs} +2 -1
  31. package/dist/chunk-FRRS2YZH.mjs +1 -0
  32. package/dist/chunk-G5TQWWQA.mjs +1 -0
  33. package/dist/{chunk-MPZFPU4X.js → chunk-GMBLPQ3I.js} +4 -3
  34. package/dist/chunk-IJFPPLQW.js +50 -0
  35. package/dist/chunk-J6OLBSZR.js +1 -0
  36. package/dist/chunk-KGGQ5NZV.js +1 -0
  37. package/dist/chunk-KHCC5UKW.mjs +1 -0
  38. package/dist/{chunk-BMFQG6RA.mjs → chunk-KJIX6V32.mjs} +108 -1885
  39. package/dist/chunk-LABHD4PU.js +109 -0
  40. package/dist/chunk-LQCVRWVF.js +1 -0
  41. package/dist/{chunk-GAIQJCAZ.js → chunk-LT5VD4KR.js} +150 -1953
  42. package/dist/{chunk-7DHKQODW.mjs → chunk-LTLCIRZY.mjs} +257 -474
  43. package/dist/chunk-N5BHXWR3.mjs +34 -0
  44. package/dist/chunk-OCO3Z5YA.js +37 -0
  45. package/dist/chunk-OFQLWSUR.mjs +1 -0
  46. package/dist/chunk-OIJ7XMDV.mjs +71 -0
  47. package/dist/chunk-ORBH4IBC.mjs +316 -0
  48. package/dist/{chunk-C4UT5V3P.js → chunk-OWHI5VGJ.js} +1 -0
  49. package/dist/chunk-OWWOAYIY.js +2652 -0
  50. package/dist/chunk-PFHOXDSW.mjs +10 -0
  51. package/dist/chunk-Q52ZEL62.mjs +1 -0
  52. package/dist/chunk-QRS7DJGS.js +103 -0
  53. package/dist/chunk-R26Y7LGJ.js +1 -0
  54. package/dist/{chunk-BFWX5GJZ.mjs → chunk-R3X4B4JJ.mjs} +56 -8
  55. package/dist/chunk-RBUYW6QQ.js +1 -0
  56. package/dist/chunk-RM7ACPTM.mjs +2601 -0
  57. package/dist/chunk-RODSGPBB.mjs +75 -0
  58. package/dist/chunk-SORWLKOK.js +1 -0
  59. package/dist/{chunk-T6ZBA6VJ.js → chunk-UHAV34YX.js} +9 -8
  60. package/dist/{chunk-GUSTCU2W.mjs → chunk-ULANYJ7Y.mjs} +1 -59
  61. package/dist/chunk-ULDE7QSN.js +70 -0
  62. package/dist/chunk-UT36VNVZ.mjs +47 -0
  63. package/dist/chunk-UY3H4PKB.js +71 -0
  64. package/dist/{chunk-KB7UXIQZ.mjs → chunk-VIVWFQG5.mjs} +3 -1
  65. package/dist/{chunk-ESZ7CBA2.js → chunk-VKBJ3SGT.js} +7 -5
  66. package/dist/{chunk-UM7WMXIU.js → chunk-W3YOQ5ZD.js} +265 -505
  67. package/dist/chunk-WOITB4JL.js +1 -0
  68. package/dist/{chunk-E42B4GSB.js → chunk-XGJL6DLV.js} +58 -7
  69. package/dist/chunk-YKZEKJMZ.mjs +1 -0
  70. package/dist/chunk-YRIBFIQ5.js +116 -0
  71. package/dist/chunk-ZFLZA7UP.mjs +1 -0
  72. package/dist/chunk-ZKUIUE7W.mjs +1 -0
  73. package/dist/chunk-ZWWJ3RRA.js +15 -0
  74. package/dist/data-grid.d.cts +241 -0
  75. package/dist/data-grid.d.ts +241 -0
  76. package/dist/data-grid.js +6486 -0
  77. package/dist/data-grid.mjs +6459 -0
  78. package/dist/data-table-CDQBo-Ve.d.ts +818 -0
  79. package/dist/data-table-jLzt6plY.d.cts +818 -0
  80. package/dist/data-table.d.cts +8 -42
  81. package/dist/data-table.d.ts +8 -42
  82. package/dist/data-table.js +61 -187
  83. package/dist/data-table.mjs +11 -5
  84. package/dist/finance.d.cts +534 -0
  85. package/dist/finance.d.ts +534 -0
  86. package/dist/finance.js +188 -0
  87. package/dist/finance.mjs +15 -0
  88. package/dist/forms.js +9 -6
  89. package/dist/forms.mjs +7 -4
  90. package/dist/{hooks-B2jU1GVT.d.ts → hooks-A55E0fgf.d.ts} +3 -2
  91. package/dist/{hooks-8ORd7T1A.d.cts → hooks-Bys_AZPI.d.cts} +3 -2
  92. package/dist/hooks.d.cts +1 -1
  93. package/dist/hooks.d.ts +1 -1
  94. package/dist/hooks.js +26 -23
  95. package/dist/hooks.mjs +6 -3
  96. package/dist/index.d.cts +536 -665
  97. package/dist/index.d.ts +536 -665
  98. package/dist/index.js +3830 -3408
  99. package/dist/index.mjs +2068 -1767
  100. package/dist/layouts.js +26 -25
  101. package/dist/layouts.mjs +5 -4
  102. package/dist/marketing-3d.js +1 -0
  103. package/dist/marketing-3d.mjs +1 -0
  104. package/dist/marketing.js +75 -74
  105. package/dist/marketing.mjs +5 -4
  106. package/dist/media.js +1 -0
  107. package/dist/media.mjs +1 -0
  108. package/dist/navigation.js +29 -28
  109. package/dist/navigation.mjs +7 -6
  110. package/dist/primitives.d.cts +72 -109
  111. package/dist/primitives.d.ts +72 -109
  112. package/dist/primitives.js +78 -72
  113. package/dist/primitives.mjs +8 -6
  114. package/dist/settings.js +9 -9
  115. package/dist/settings.mjs +4 -4
  116. package/package.json +21 -4
  117. package/dist/UnifiedTableControls-CG299y9h.d.ts +0 -1233
  118. package/dist/UnifiedTableControls-CIjRpNhy.d.cts +0 -1233
  119. package/dist/chunk-GMBGWOCR.mjs +0 -48
  120. package/dist/chunk-HBLKVQIQ.mjs +0 -23
  121. package/dist/chunk-HMAMMC72.js +0 -26
  122. package/dist/chunk-MVYRNJA6.js +0 -74
@@ -0,0 +1,2601 @@
1
+ "use client";
2
+ import { buildSpreadsheetWorkbookXml, downloadExcelXml } from './chunk-OIJ7XMDV.mjs';
3
+ import { Label } from './chunk-KHCC5UKW.mjs';
4
+ import { dataTableTopperButtonProps, dataTableTopperResponsiveClasses, dataTableTopperOpenStateClasses, dataTableTopperIconClasses } from './chunk-PFHOXDSW.mjs';
5
+ import { TableRow, TableCell, Table, TableHeader, TableHead, TableBody, TableFooter } from './chunk-APFEP5B7.mjs';
6
+ import { Skeleton, useDebouncedCallback } from './chunk-UT36VNVZ.mjs';
7
+ import { Badge } from './chunk-ULANYJ7Y.mjs';
8
+ import { Calendar, Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator } from './chunk-ORBH4IBC.mjs';
9
+ import { Popover, PopoverTrigger, PopoverContent } from './chunk-RODSGPBB.mjs';
10
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from './chunk-5THF4YP6.mjs';
11
+ import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, SelectGroup } from './chunk-6BUBNZPG.mjs';
12
+ import { Button } from './chunk-VBD4Q5LL.mjs';
13
+ import { Separator } from './chunk-ZKUIUE7W.mjs';
14
+ import { SizedSpinner } from './chunk-N5BHXWR3.mjs';
15
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem, DropdownMenuCheckboxItem } from './chunk-OFQLWSUR.mjs';
16
+ import { Tooltip, TooltipTrigger, TooltipContent } from './chunk-YKZEKJMZ.mjs';
17
+ import { Input } from './chunk-STEP6C4C.mjs';
18
+ import { cn } from './chunk-IMKLN273.mjs';
19
+ import { Download, FileText, FileSpreadsheet, Search, X, ChevronDown, LayoutGrid, Star, Check, Trash2, Save, Plus, ChevronsLeft, ChevronLeft, ChevronRight, ChevronsRight, ChevronUp, ChevronsUpDown, EyeOff, XCircle, CalendarIcon, PlusCircle, Settings2, MoreHorizontal } from 'lucide-react';
20
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
21
+ import * as React12 from 'react';
22
+ import { cva } from 'class-variance-authority';
23
+ import { formatDate } from '@caffeinebounce/shared-utils';
24
+ import { flexRender, useReactTable, getFacetedMinMaxValues, getFacetedUniqueValues, getFacetedRowModel, getSortedRowModel, getPaginationRowModel, getFilteredRowModel, getCoreRowModel } from '@tanstack/react-table';
25
+ import * as SliderPrimitive from '@radix-ui/react-slider';
26
+ import { createParser } from 'nuqs/server';
27
+ import { z } from 'zod';
28
+ import { useQueryState, parseAsInteger, parseAsArrayOf, parseAsString, useQueryStates } from 'nuqs';
29
+
30
+ function DataTableAddButton({
31
+ label = "Add",
32
+ icon,
33
+ responsiveLabel = true,
34
+ className,
35
+ children,
36
+ ...props
37
+ }) {
38
+ const fontSizeClass = "text-xs";
39
+ const iconElement = icon ?? /* @__PURE__ */ jsx(Plus, { className: "size-4" });
40
+ return /* @__PURE__ */ jsxs(
41
+ Button,
42
+ {
43
+ ...dataTableTopperButtonProps,
44
+ className: cn(
45
+ fontSizeClass,
46
+ responsiveLabel ? dataTableTopperResponsiveClasses : "px-2 w-auto",
47
+ className
48
+ ),
49
+ ...props,
50
+ children: [
51
+ iconElement,
52
+ responsiveLabel ? /* @__PURE__ */ jsx("span", { className: "hidden @min-[450px]:inline", children: children ?? label }) : /* @__PURE__ */ jsx("span", { children: children ?? label })
53
+ ]
54
+ }
55
+ );
56
+ }
57
+ function escapeCsvField(value) {
58
+ if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
59
+ return `"${value.replace(/"/g, '""')}"`;
60
+ }
61
+ return value;
62
+ }
63
+ function formatCsvValue(value) {
64
+ if (value === null || value === void 0) {
65
+ return "";
66
+ }
67
+ if (typeof value === "boolean") {
68
+ return value ? "Yes" : "No";
69
+ }
70
+ if (value instanceof Date) {
71
+ return value.toISOString();
72
+ }
73
+ if (typeof value === "object") {
74
+ try {
75
+ return JSON.stringify(value);
76
+ } catch {
77
+ return String(value);
78
+ }
79
+ }
80
+ return String(value);
81
+ }
82
+ function serializeTableExport({
83
+ table,
84
+ visibleColumnsOnly = true,
85
+ selectedRowsOnly = false,
86
+ customHeaders = {},
87
+ excludeColumns = [],
88
+ formatters = {}
89
+ }) {
90
+ const allColumns = visibleColumnsOnly ? table.getVisibleLeafColumns() : table.getAllLeafColumns();
91
+ const columns = allColumns.filter((col) => {
92
+ const colId = col.id;
93
+ if (["select", "selection", "actions", "_actions"].includes(colId)) {
94
+ return false;
95
+ }
96
+ return !excludeColumns.includes(colId);
97
+ });
98
+ const tableRows = selectedRowsOnly ? table.getFilteredSelectedRowModel().rows : table.getFilteredRowModel().rows;
99
+ return {
100
+ headers: columns.map((col) => customHeaders[col.id] ?? col.id),
101
+ rows: tableRows.map(
102
+ (row) => columns.map((col) => {
103
+ const cellValue = row.getValue(col.id);
104
+ const formatter = formatters[col.id];
105
+ return formatter ? formatter(cellValue) : formatCsvValue(cellValue);
106
+ })
107
+ )
108
+ };
109
+ }
110
+ function exportToCsv({
111
+ table,
112
+ filename = "export",
113
+ visibleColumnsOnly = true,
114
+ selectedRowsOnly = false,
115
+ customHeaders = {},
116
+ excludeColumns = [],
117
+ formatters = {}
118
+ }) {
119
+ const { headers, rows } = serializeTableExport({
120
+ table,
121
+ visibleColumnsOnly,
122
+ selectedRowsOnly,
123
+ customHeaders,
124
+ excludeColumns,
125
+ formatters
126
+ });
127
+ const csvContent = [
128
+ headers.map(escapeCsvField).join(","),
129
+ ...rows.map((row) => row.map(escapeCsvField).join(","))
130
+ ].join("\n");
131
+ const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
132
+ const url = URL.createObjectURL(blob);
133
+ const link = document.createElement("a");
134
+ link.setAttribute("href", url);
135
+ link.setAttribute("download", `${filename}.csv`);
136
+ link.style.visibility = "hidden";
137
+ document.body.appendChild(link);
138
+ link.click();
139
+ document.body.removeChild(link);
140
+ URL.revokeObjectURL(url);
141
+ }
142
+ function exportToExcel({
143
+ table,
144
+ filename = "export",
145
+ visibleColumnsOnly = true,
146
+ selectedRowsOnly = false,
147
+ customHeaders = {},
148
+ excludeColumns = [],
149
+ formatters = {}
150
+ }) {
151
+ const { headers, rows } = serializeTableExport({
152
+ table,
153
+ visibleColumnsOnly,
154
+ selectedRowsOnly,
155
+ customHeaders,
156
+ excludeColumns,
157
+ formatters
158
+ });
159
+ const sheetRows = [
160
+ headers.map((header) => ({ value: header, style: "header" })),
161
+ ...rows.map(
162
+ (row) => row.map((cell) => {
163
+ const trimmed = cell.trim();
164
+ const isNumericPattern = trimmed !== "" && /^-?\d+(\.\d+)?$/.test(trimmed);
165
+ const hasLeadingZero = /^0\d+$/.test(trimmed) || /^-0\d+$/.test(trimmed);
166
+ const numValue = Number(trimmed);
167
+ const isNumber = isNumericPattern && !hasLeadingZero && !Number.isNaN(numValue);
168
+ if (isNumber) {
169
+ return {
170
+ value: numValue,
171
+ type: "Number",
172
+ style: "number"
173
+ };
174
+ }
175
+ return { value: cell, style: "text" };
176
+ })
177
+ )
178
+ ];
179
+ const xmlContent = buildSpreadsheetWorkbookXml({
180
+ worksheetName: "Data",
181
+ rows: sheetRows
182
+ });
183
+ downloadExcelXml(xmlContent, filename);
184
+ }
185
+ function DataTableExportButton({
186
+ table,
187
+ onExportCsv,
188
+ onExportExcel,
189
+ onExport,
190
+ // deprecated, maps to CSV
191
+ filename = "export",
192
+ label = "Export",
193
+ disabled = false,
194
+ selectedRowsOnly = false,
195
+ excludeColumns = [],
196
+ customHeaders = {},
197
+ formatters = {}
198
+ }) {
199
+ const fontSizeClass = "text-xs";
200
+ const [isExporting, setIsExporting] = React12.useState(false);
201
+ const [exportingFormat, setExportingFormat] = React12.useState(null);
202
+ const handleExport = React12.useCallback(
203
+ async (format) => {
204
+ if (disabled) return;
205
+ setIsExporting(true);
206
+ setExportingFormat(format);
207
+ try {
208
+ if (table) {
209
+ if (format === "csv") {
210
+ exportToCsv({
211
+ table,
212
+ filename,
213
+ selectedRowsOnly,
214
+ excludeColumns,
215
+ customHeaders,
216
+ formatters
217
+ });
218
+ } else {
219
+ exportToExcel({
220
+ table,
221
+ filename,
222
+ selectedRowsOnly,
223
+ excludeColumns,
224
+ customHeaders,
225
+ formatters
226
+ });
227
+ }
228
+ } else {
229
+ if (format === "csv") {
230
+ await (onExportCsv ?? onExport)?.();
231
+ } else {
232
+ await onExportExcel?.();
233
+ }
234
+ }
235
+ } finally {
236
+ setIsExporting(false);
237
+ setExportingFormat(null);
238
+ }
239
+ },
240
+ [
241
+ table,
242
+ onExportCsv,
243
+ onExportExcel,
244
+ onExport,
245
+ filename,
246
+ selectedRowsOnly,
247
+ excludeColumns,
248
+ customHeaders,
249
+ formatters,
250
+ disabled
251
+ ]
252
+ );
253
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
254
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
255
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
256
+ Button,
257
+ {
258
+ ...dataTableTopperButtonProps,
259
+ disabled: isExporting || disabled,
260
+ "aria-label": label,
261
+ className: dataTableTopperOpenStateClasses,
262
+ children: isExporting ? /* @__PURE__ */ jsx(SizedSpinner, { className: "size-4" }) : /* @__PURE__ */ jsx(Download, { className: "size-4" })
263
+ }
264
+ ) }) }),
265
+ /* @__PURE__ */ jsx(TooltipContent, { className: fontSizeClass, children: label })
266
+ ] }),
267
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-44", children: [
268
+ /* @__PURE__ */ jsx(
269
+ DropdownMenuLabel,
270
+ {
271
+ className: cn("font-normal text-muted-foreground", fontSizeClass),
272
+ children: "Export Data"
273
+ }
274
+ ),
275
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
276
+ /* @__PURE__ */ jsxs(
277
+ DropdownMenuItem,
278
+ {
279
+ onClick: () => handleExport("csv"),
280
+ disabled: isExporting,
281
+ className: cn("gap-2", fontSizeClass),
282
+ children: [
283
+ /* @__PURE__ */ jsx(FileText, { className: dataTableTopperIconClasses }),
284
+ /* @__PURE__ */ jsx("span", { children: "CSV" }),
285
+ exportingFormat === "csv" && /* @__PURE__ */ jsx(SizedSpinner, { className: "size-3 ml-auto" })
286
+ ]
287
+ }
288
+ ),
289
+ /* @__PURE__ */ jsxs(
290
+ DropdownMenuItem,
291
+ {
292
+ onClick: () => handleExport("excel"),
293
+ disabled: isExporting,
294
+ className: cn("gap-2", fontSizeClass),
295
+ children: [
296
+ /* @__PURE__ */ jsx(FileSpreadsheet, { className: dataTableTopperIconClasses }),
297
+ /* @__PURE__ */ jsx("span", { children: "Excel" }),
298
+ exportingFormat === "excel" && /* @__PURE__ */ jsx(SizedSpinner, { className: "size-3 ml-auto" })
299
+ ]
300
+ }
301
+ )
302
+ ] })
303
+ ] });
304
+ }
305
+ var iconButtonVariants = cva(
306
+ "inline-flex items-center justify-center rounded-box transition-colors duration-200 cursor-pointer disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
307
+ {
308
+ variants: {
309
+ variant: {
310
+ default: "text-muted-foreground hover:text-foreground hover:bg-accent",
311
+ ghost: "text-muted-foreground/50 hover:text-foreground hover:bg-transparent",
312
+ delete: "text-muted-foreground/50 hover:text-destructive hover:bg-transparent",
313
+ edit: "text-muted-foreground/50 hover:text-foreground hover:bg-transparent",
314
+ destructive: "text-muted-foreground/50 hover:text-destructive hover:bg-transparent",
315
+ success: "text-muted-foreground/50 hover:text-green-600 hover:bg-transparent",
316
+ successActive: "text-green-600 hover:text-muted-foreground/60 hover:bg-transparent"
317
+ },
318
+ size: {
319
+ default: "h-8 w-8 [&_svg]:size-4",
320
+ sm: "h-6 w-6 [&_svg]:size-3.5",
321
+ xs: "h-5 w-5 [&_svg]:size-3",
322
+ lg: "h-10 w-10 [&_svg]:size-5"
323
+ }
324
+ },
325
+ defaultVariants: {
326
+ variant: "default",
327
+ size: "default"
328
+ }
329
+ }
330
+ );
331
+ function IconButton({ className, variant, size, ...props }) {
332
+ return /* @__PURE__ */ jsx(
333
+ "button",
334
+ {
335
+ type: "button",
336
+ "data-slot": "icon-button",
337
+ className: cn(iconButtonVariants({ variant, size, className })),
338
+ ...props
339
+ }
340
+ );
341
+ }
342
+ function useIsDesktop() {
343
+ const [isDesktop, setIsDesktop] = React12.useState(false);
344
+ React12.useEffect(() => {
345
+ const mediaQuery = window.matchMedia("(min-width: 768px)");
346
+ setIsDesktop(mediaQuery.matches);
347
+ const handler = (e) => setIsDesktop(e.matches);
348
+ mediaQuery.addEventListener("change", handler);
349
+ return () => mediaQuery.removeEventListener("change", handler);
350
+ }, []);
351
+ return isDesktop;
352
+ }
353
+ function ActionsDropdown({
354
+ actions,
355
+ fontSizeClass,
356
+ density
357
+ }) {
358
+ const isCompact = density === "compact";
359
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
360
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
361
+ IconButton,
362
+ {
363
+ variant: "ghost",
364
+ size: isCompact ? "xs" : "sm",
365
+ className: "data-[state=open]:bg-muted",
366
+ children: [
367
+ /* @__PURE__ */ jsx(MoreHorizontal, { className: isCompact ? "size-3.5" : "size-4" }),
368
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Open menu" })
369
+ ]
370
+ }
371
+ ) }),
372
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", className: "w-40", children: actions.map((action, index) => /* @__PURE__ */ jsxs("div", { children: [
373
+ action.separatorBefore && index > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
374
+ /* @__PURE__ */ jsxs(
375
+ DropdownMenuItem,
376
+ {
377
+ onClick: action.onClick,
378
+ disabled: action.disabled,
379
+ className: cn(
380
+ fontSizeClass,
381
+ action.destructive && "hover:text-destructive hover:bg-destructive/10",
382
+ action.success && "hover:text-success hover:bg-success/10",
383
+ action.successActive && "text-green-600 hover:text-muted-foreground hover:bg-accent"
384
+ ),
385
+ children: [
386
+ action.icon && /* @__PURE__ */ jsx(
387
+ "span",
388
+ {
389
+ className: cn(
390
+ "mr-2",
391
+ action.destructive && "group-hover:text-destructive",
392
+ action.success && "group-hover:text-success",
393
+ action.successActive && "text-green-600 group-hover:text-muted-foreground"
394
+ ),
395
+ children: action.icon
396
+ }
397
+ ),
398
+ action.label
399
+ ]
400
+ }
401
+ )
402
+ ] }, action.label)) })
403
+ ] });
404
+ }
405
+ function ActionsInline({
406
+ actions,
407
+ fontSizeClass,
408
+ density
409
+ }) {
410
+ const isCompact = density === "compact";
411
+ return /* @__PURE__ */ jsx("div", { className: cn("flex items-center", isCompact ? "gap-0.5" : "gap-1"), children: actions.map((action) => {
412
+ const variant = action.destructive ? "delete" : action.successActive ? "successActive" : action.success ? "success" : "ghost";
413
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
414
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
415
+ IconButton,
416
+ {
417
+ variant,
418
+ size: isCompact ? "xs" : "default",
419
+ onClick: action.onClick,
420
+ disabled: action.disabled,
421
+ children: [
422
+ action.icon,
423
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: action.label })
424
+ ]
425
+ }
426
+ ) }),
427
+ /* @__PURE__ */ jsx(TooltipContent, { className: fontSizeClass, children: action.label })
428
+ ] }, action.label);
429
+ }) });
430
+ }
431
+ function DataTableRowActions({
432
+ actions,
433
+ mode = "dropdown"
434
+ }) {
435
+ const fontSizeClass = "text-xs";
436
+ const density = "comfy";
437
+ const isDesktop = useIsDesktop();
438
+ if (actions.length === 0) return null;
439
+ if (mode === "dropdown") {
440
+ return /* @__PURE__ */ jsx(
441
+ ActionsDropdown,
442
+ {
443
+ actions,
444
+ fontSizeClass,
445
+ density
446
+ }
447
+ );
448
+ }
449
+ if (mode === "inline") {
450
+ return /* @__PURE__ */ jsx(
451
+ ActionsInline,
452
+ {
453
+ actions,
454
+ fontSizeClass,
455
+ density
456
+ }
457
+ );
458
+ }
459
+ if (isDesktop) {
460
+ return /* @__PURE__ */ jsx(
461
+ ActionsInline,
462
+ {
463
+ actions,
464
+ fontSizeClass,
465
+ density
466
+ }
467
+ );
468
+ }
469
+ return /* @__PURE__ */ jsx(
470
+ ActionsDropdown,
471
+ {
472
+ actions,
473
+ fontSizeClass,
474
+ density
475
+ }
476
+ );
477
+ }
478
+ function DataTableSearch({
479
+ searchValue = "",
480
+ searchPlaceholder = "Search...",
481
+ onSearchChange,
482
+ className
483
+ }) {
484
+ const fontSizeClass = "text-xs";
485
+ const [isExpanded, setIsExpanded] = React12.useState(false);
486
+ const inputRef = React12.useRef(null);
487
+ React12.useEffect(() => {
488
+ if (searchValue && !isExpanded) {
489
+ setIsExpanded(true);
490
+ }
491
+ }, [searchValue, isExpanded]);
492
+ React12.useEffect(() => {
493
+ if (isExpanded && inputRef.current) {
494
+ inputRef.current.focus();
495
+ }
496
+ }, [isExpanded]);
497
+ const handleBlur = () => {
498
+ if (!searchValue) {
499
+ setIsExpanded(false);
500
+ }
501
+ };
502
+ const handleClear = () => {
503
+ onSearchChange?.("");
504
+ setIsExpanded(false);
505
+ };
506
+ return /* @__PURE__ */ jsx("div", { className: cn("relative flex items-center", className), children: /* @__PURE__ */ jsxs(
507
+ "div",
508
+ {
509
+ className: cn(
510
+ "flex items-center rounded-md border border-transparent transition-all duration-200 ease-out",
511
+ isExpanded ? "w-48 border-input bg-background" : "w-8 cursor-pointer"
512
+ ),
513
+ children: [
514
+ /* @__PURE__ */ jsx(
515
+ "button",
516
+ {
517
+ type: "button",
518
+ onClick: () => !isExpanded && setIsExpanded(true),
519
+ className: cn(
520
+ "flex items-center justify-center shrink-0 transition-colors rounded-md",
521
+ dataTableTopperIconClasses,
522
+ isExpanded ? "size-8 cursor-default" : "size-8"
523
+ ),
524
+ "aria-label": isExpanded ? void 0 : "Search",
525
+ children: /* @__PURE__ */ jsx(Search, { className: "size-4" })
526
+ }
527
+ ),
528
+ /* @__PURE__ */ jsx(
529
+ "input",
530
+ {
531
+ ref: inputRef,
532
+ type: "text",
533
+ placeholder: searchPlaceholder,
534
+ value: searchValue,
535
+ onChange: (e) => onSearchChange?.(e.target.value),
536
+ onBlur: handleBlur,
537
+ className: cn(
538
+ "h-8 bg-transparent outline-none placeholder:text-muted-foreground transition-all duration-200",
539
+ fontSizeClass,
540
+ isExpanded ? "w-full pr-7 opacity-100" : "w-0 opacity-0"
541
+ )
542
+ }
543
+ ),
544
+ isExpanded && searchValue && /* @__PURE__ */ jsx(
545
+ "button",
546
+ {
547
+ type: "button",
548
+ onClick: handleClear,
549
+ className: "absolute right-1.5 flex items-center justify-center size-5 rounded-sm hover:bg-accent/50",
550
+ "aria-label": "Clear search",
551
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5 text-muted-foreground" })
552
+ }
553
+ )
554
+ ]
555
+ }
556
+ ) });
557
+ }
558
+ var summaryOptions = {
559
+ text: [
560
+ { value: "none", label: "None" },
561
+ { value: "count", label: "Count" },
562
+ { value: "count_unique", label: "Count unique" },
563
+ { value: "percent_empty", label: "% Empty" },
564
+ { value: "percent_filled", label: "% Filled" }
565
+ ],
566
+ number: [
567
+ { value: "none", label: "None" },
568
+ { value: "count", label: "Count" },
569
+ { value: "sum", label: "Sum" },
570
+ { value: "average", label: "Average" },
571
+ { value: "median", label: "Median" },
572
+ { value: "min", label: "Min" },
573
+ { value: "max", label: "Max" },
574
+ { value: "range", label: "Range" },
575
+ { value: "percent_empty", label: "% Empty" },
576
+ { value: "percent_filled", label: "% Filled" }
577
+ ],
578
+ boolean: [
579
+ { value: "none", label: "None" },
580
+ { value: "count", label: "Count" },
581
+ { value: "percent_empty", label: "% Empty" },
582
+ { value: "percent_filled", label: "% Filled" }
583
+ ],
584
+ date: [
585
+ { value: "none", label: "None" },
586
+ { value: "count", label: "Count" },
587
+ { value: "min", label: "Earliest" },
588
+ { value: "max", label: "Latest" },
589
+ { value: "range", label: "Date range" },
590
+ { value: "percent_empty", label: "% Empty" },
591
+ { value: "percent_filled", label: "% Filled" }
592
+ ]
593
+ };
594
+ function calculateSummary(column, allData, type, dataType) {
595
+ if (type === "none") return "";
596
+ const accessor = column.accessorFn;
597
+ if (!accessor) return "";
598
+ const allValues = allData.map((row) => accessor(row, 0)).filter((v) => v !== null && v !== void 0 && v !== "");
599
+ const totalCount = allData.length;
600
+ const filledCount = allValues.length;
601
+ const emptyCount = totalCount - filledCount;
602
+ switch (type) {
603
+ case "count":
604
+ return `Count: ${filledCount.toLocaleString()}`;
605
+ case "count_unique": {
606
+ const uniqueValues = new Set(allValues.map((v) => String(v)));
607
+ return `Unique: ${uniqueValues.size.toLocaleString()}`;
608
+ }
609
+ case "percent_empty":
610
+ return totalCount > 0 ? `Empty: ${(emptyCount / totalCount * 100).toFixed(1)}%` : "Empty: 0%";
611
+ case "percent_filled":
612
+ return totalCount > 0 ? `Filled: ${(filledCount / totalCount * 100).toFixed(1)}%` : "Filled: 0%";
613
+ case "sum":
614
+ case "average":
615
+ case "median":
616
+ case "min":
617
+ case "max":
618
+ case "range": {
619
+ if (dataType === "number") {
620
+ const numericValues = allValues.map((v) => Number(v)).filter((n) => !Number.isNaN(n));
621
+ if (numericValues.length === 0) return "\u2014";
622
+ switch (type) {
623
+ case "sum": {
624
+ const sum = numericValues.reduce((a, b) => a + b, 0);
625
+ return `Sum: ${formatNumber(sum)}`;
626
+ }
627
+ case "average": {
628
+ const avg = numericValues.reduce((a, b) => a + b, 0) / numericValues.length;
629
+ return `Avg: ${formatNumber(avg)}`;
630
+ }
631
+ case "median": {
632
+ const sorted = [...numericValues].sort((a, b) => a - b);
633
+ const mid = Math.floor(sorted.length / 2);
634
+ const median = sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
635
+ return `Median: ${formatNumber(median)}`;
636
+ }
637
+ case "min":
638
+ return `Min: ${formatNumber(Math.min(...numericValues))}`;
639
+ case "max":
640
+ return `Max: ${formatNumber(Math.max(...numericValues))}`;
641
+ case "range": {
642
+ const min = Math.min(...numericValues);
643
+ const max = Math.max(...numericValues);
644
+ return `${formatNumber(min)} \u2013 ${formatNumber(max)}`;
645
+ }
646
+ }
647
+ }
648
+ if (dataType === "date") {
649
+ const dateValues = allValues.map((v) => {
650
+ const d = v instanceof Date ? v : new Date(String(v));
651
+ return d.getTime();
652
+ }).filter((t) => !Number.isNaN(t));
653
+ if (dateValues.length === 0) return "\u2014";
654
+ switch (type) {
655
+ case "min":
656
+ return formatDate(new Date(Math.min(...dateValues)));
657
+ case "max":
658
+ return formatDate(new Date(Math.max(...dateValues)));
659
+ case "range": {
660
+ const min = new Date(Math.min(...dateValues));
661
+ const max = new Date(Math.max(...dateValues));
662
+ return `${formatDate(min)} \u2013 ${formatDate(max)}`;
663
+ }
664
+ default:
665
+ return "\u2014";
666
+ }
667
+ }
668
+ return "\u2014";
669
+ }
670
+ default:
671
+ return "";
672
+ }
673
+ }
674
+ function formatNumber(n) {
675
+ if (Number.isInteger(n)) {
676
+ return n.toLocaleString();
677
+ }
678
+ return n.toLocaleString(void 0, {
679
+ minimumFractionDigits: 2,
680
+ maximumFractionDigits: 2
681
+ });
682
+ }
683
+ function DataTableSummary({
684
+ table,
685
+ allData,
686
+ summaryConfig,
687
+ onSummaryChange,
688
+ getColumnDataType,
689
+ gutterWidth = 0,
690
+ className
691
+ }) {
692
+ const visibleColumns = table.getVisibleLeafColumns().filter((col) => col.id !== "select" && col.id !== "actions");
693
+ const [hoveredColumnId, setHoveredColumnId] = React12.useState(
694
+ null
695
+ );
696
+ const detectDataType = React12.useCallback(
697
+ (columnId) => {
698
+ if (getColumnDataType) return getColumnDataType(columnId);
699
+ const column = table.getColumn(columnId);
700
+ if (!column) return "text";
701
+ const meta = column.columnDef.meta;
702
+ if (meta?.filterType === "number") return "number";
703
+ if (meta?.filterType === "boolean") return "boolean";
704
+ const accessor = column.accessorFn;
705
+ if (!accessor) return "text";
706
+ for (const row of allData) {
707
+ const value = accessor(row, 0);
708
+ if (value === null || value === void 0) continue;
709
+ if (typeof value === "number") return "number";
710
+ if (typeof value === "boolean") return "boolean";
711
+ if (value instanceof Date) return "date";
712
+ if (typeof value === "string" && !Number.isNaN(Date.parse(value))) {
713
+ const parsed = new Date(value);
714
+ if (parsed.getFullYear() > 1900 && parsed.getFullYear() < 2100) {
715
+ return "date";
716
+ }
717
+ }
718
+ break;
719
+ }
720
+ return "text";
721
+ },
722
+ [getColumnDataType, table, allData]
723
+ );
724
+ return /* @__PURE__ */ jsxs(
725
+ TableRow,
726
+ {
727
+ className: cn("hover:bg-transparent border-0 bg-transparent", className),
728
+ children: [
729
+ gutterWidth > 0 && /* @__PURE__ */ jsx(TableCell, { className: "p-0 border-0", style: { width: gutterWidth } }),
730
+ visibleColumns.map((column, index) => {
731
+ const columnId = column.id;
732
+ const dataType = detectDataType(columnId);
733
+ const currentType = summaryConfig[columnId] ?? "none";
734
+ const options = summaryOptions[dataType] ?? summaryOptions.text;
735
+ const summaryValue = calculateSummary(
736
+ column,
737
+ allData,
738
+ currentType,
739
+ dataType
740
+ );
741
+ const isHovered = hoveredColumnId === columnId;
742
+ const isLastColumn = index === visibleColumns.length - 1;
743
+ const isFirstColumn = index === 0;
744
+ return /* @__PURE__ */ jsx(
745
+ TableCell,
746
+ {
747
+ className: cn(
748
+ "p-0 border-0",
749
+ isLastColumn && "rounded-br-md",
750
+ isFirstColumn && "rounded-bl-md"
751
+ ),
752
+ style: { width: column.getSize(), minWidth: column.getSize() },
753
+ children: /* @__PURE__ */ jsx(
754
+ SummaryCell,
755
+ {
756
+ columnId,
757
+ column,
758
+ currentType,
759
+ summaryValue,
760
+ options,
761
+ isHovered,
762
+ onSummaryChange,
763
+ onMouseEnter: () => setHoveredColumnId(columnId),
764
+ onMouseLeave: () => setHoveredColumnId(null)
765
+ }
766
+ )
767
+ },
768
+ columnId
769
+ );
770
+ })
771
+ ]
772
+ }
773
+ );
774
+ }
775
+ function SummaryCell({
776
+ columnId,
777
+ currentType,
778
+ summaryValue,
779
+ options,
780
+ isHovered,
781
+ onSummaryChange,
782
+ onMouseEnter,
783
+ onMouseLeave
784
+ }) {
785
+ const [isOpen, setIsOpen] = React12.useState(false);
786
+ const showCalculate = currentType === "none" && (isHovered || isOpen);
787
+ return (
788
+ // biome-ignore lint/a11y/noStaticElementInteractions: Hover state for visual feedback only
789
+ /* @__PURE__ */ jsx(
790
+ "div",
791
+ {
792
+ className: cn(
793
+ "flex items-center min-w-0",
794
+ "px-2 py-1"
795
+ ),
796
+ onMouseEnter,
797
+ onMouseLeave,
798
+ role: "presentation",
799
+ children: /* @__PURE__ */ jsxs(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
800
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
801
+ "button",
802
+ {
803
+ type: "button",
804
+ className: cn(
805
+ "group flex items-center gap-1 text-xs transition-colors rounded px-1 py-0.5 -mx-1 focus:outline-none focus-visible:outline-none",
806
+ currentType === "none" ? "text-muted-foreground/50 hover:text-muted-foreground" : "text-muted-foreground hover:text-foreground"
807
+ ),
808
+ children: [
809
+ currentType === "none" ? /* @__PURE__ */ jsx(
810
+ "span",
811
+ {
812
+ className: cn(
813
+ "italic transition-opacity",
814
+ showCalculate ? "opacity-100" : "opacity-0"
815
+ ),
816
+ children: "Calculate"
817
+ }
818
+ ) : /* @__PURE__ */ jsx("span", { className: "truncate italic pr-1", children: summaryValue }),
819
+ /* @__PURE__ */ jsx(
820
+ ChevronDown,
821
+ {
822
+ className: cn(
823
+ "size-3 shrink-0 transition-opacity",
824
+ currentType !== "none" ? "opacity-0 group-hover:opacity-50" : "opacity-0"
825
+ )
826
+ }
827
+ )
828
+ ]
829
+ }
830
+ ) }),
831
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: "w-40", children: options.map((option) => /* @__PURE__ */ jsx(
832
+ DropdownMenuItem,
833
+ {
834
+ onClick: () => onSummaryChange(columnId, option.value),
835
+ className: cn(
836
+ "text-xs",
837
+ currentType === option.value && "bg-accent"
838
+ ),
839
+ children: option.label
840
+ },
841
+ option.value
842
+ )) })
843
+ ] })
844
+ }
845
+ )
846
+ );
847
+ }
848
+ function DataTableTopper({
849
+ tabs,
850
+ activeTab,
851
+ onTabChange,
852
+ gutterWidth = 0,
853
+ className,
854
+ children,
855
+ ...props
856
+ }) {
857
+ return /* @__PURE__ */ jsx(
858
+ "div",
859
+ {
860
+ className: cn(
861
+ // Container context for responsive layout based on available width
862
+ "@container w-full min-w-0 shrink-0",
863
+ // Visual styling
864
+ "border-b border-border/40 pb-1",
865
+ className
866
+ ),
867
+ ...props,
868
+ children: /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-row items-center justify-between gap-3", children: [
869
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 shrink-0 items-center gap-0.5", children: [
870
+ gutterWidth > 0 && /* @__PURE__ */ jsx("div", { className: "shrink-0", style: { width: gutterWidth } }),
871
+ tabs && tabs.length > 0 && /* @__PURE__ */ jsx("div", { className: "block @min-[450px]:hidden", children: /* @__PURE__ */ jsxs(Select, { value: activeTab, onValueChange: onTabChange, children: [
872
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-7 w-[100px] text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select tab" }) }),
873
+ /* @__PURE__ */ jsx(SelectContent, { children: tabs.map((tab) => /* @__PURE__ */ jsx(SelectItem, { value: tab.id, children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
874
+ tab.label,
875
+ tab.count !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: tab.count })
876
+ ] }) }, tab.id)) })
877
+ ] }) }),
878
+ /* @__PURE__ */ jsx(
879
+ "div",
880
+ {
881
+ className: cn(
882
+ "items-center gap-0.5 overflow-x-auto no-scrollbar",
883
+ tabs && tabs.length > 0 ? "hidden @min-[450px]:flex" : "flex"
884
+ ),
885
+ children: tabs?.map((tab) => /* @__PURE__ */ jsxs(
886
+ "button",
887
+ {
888
+ type: "button",
889
+ onClick: () => onTabChange?.(tab.id),
890
+ className: cn(
891
+ "relative flex items-center gap-1.5 px-2 py-1 text-sm transition-colors rounded-md whitespace-nowrap",
892
+ activeTab === tab.id ? "text-foreground font-medium" : "text-muted-foreground hover:text-foreground hover:bg-accent/50"
893
+ ),
894
+ children: [
895
+ tab.label,
896
+ tab.count !== void 0 && /* @__PURE__ */ jsx(
897
+ "span",
898
+ {
899
+ className: cn(
900
+ "text-xs tabular-nums",
901
+ activeTab === tab.id ? "text-muted-foreground" : "text-muted-foreground/60"
902
+ ),
903
+ children: tab.count
904
+ }
905
+ ),
906
+ activeTab === tab.id && /* @__PURE__ */ jsx("span", { className: "absolute bottom-0 left-2 right-2 h-0.5 bg-foreground rounded-full" })
907
+ ]
908
+ },
909
+ tab.id
910
+ ))
911
+ }
912
+ )
913
+ ] }),
914
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children })
915
+ ] })
916
+ }
917
+ );
918
+ }
919
+ function hasUnsavedChanges(currentState, activeView) {
920
+ if (!activeView) return false;
921
+ const visA = JSON.stringify(currentState.columnVisibility ?? {});
922
+ const visB = JSON.stringify(activeView.columnVisibility ?? {});
923
+ if (visA !== visB) return true;
924
+ const filtA = JSON.stringify(currentState.filters ?? []);
925
+ const filtB = JSON.stringify(activeView.filters ?? []);
926
+ if (filtA !== filtB) return true;
927
+ const sortA = JSON.stringify(currentState.sorting ?? []);
928
+ const sortB = JSON.stringify(activeView.sorting ?? []);
929
+ if (sortA !== sortB) return true;
930
+ const orderA = JSON.stringify(currentState.columnOrder ?? []);
931
+ const orderB = JSON.stringify(activeView.columnOrder ?? []);
932
+ if (orderA !== orderB) return true;
933
+ const wrapA = JSON.stringify(currentState.columnWrapping ?? {});
934
+ const wrapB = JSON.stringify(activeView.columnWrapping ?? {});
935
+ if (wrapA !== wrapB) return true;
936
+ const rowA = JSON.stringify(currentState.rowOrder ?? []);
937
+ const rowB = JSON.stringify(activeView.rowOrder ?? []);
938
+ if (rowA !== rowB) return true;
939
+ return false;
940
+ }
941
+ function DataTableViews({
942
+ views,
943
+ activeViewId,
944
+ currentState,
945
+ onSelectView,
946
+ onSaveView,
947
+ onUpdateView,
948
+ onDeleteView,
949
+ onSetDefaultView,
950
+ className
951
+ }) {
952
+ const fontSizeClass = "text-xs";
953
+ const [saveDialogOpen, setSaveDialogOpen] = React12.useState(false);
954
+ const [newViewName, setNewViewName] = React12.useState("");
955
+ const [setAsDefault, setSetAsDefault] = React12.useState(false);
956
+ const [nameError, setNameError] = React12.useState(null);
957
+ const activeView = views.find((v) => v.id === activeViewId);
958
+ views.find((v) => v.isDefault);
959
+ const hasChanges = hasUnsavedChanges(currentState, activeView);
960
+ const checkDuplicateName = (name) => {
961
+ const trimmedName = name.trim();
962
+ if (!trimmedName) {
963
+ setNameError(null);
964
+ return;
965
+ }
966
+ const isDuplicate = views.some(
967
+ (v) => v.name.toLowerCase() === trimmedName.toLowerCase()
968
+ );
969
+ setNameError(isDuplicate ? "A view with this name already exists" : null);
970
+ };
971
+ const handleSaveNewView = () => {
972
+ if (!newViewName.trim()) return;
973
+ const trimmedName = newViewName.trim();
974
+ const isDuplicate = views.some(
975
+ (v) => v.name.toLowerCase() === trimmedName.toLowerCase()
976
+ );
977
+ if (isDuplicate) {
978
+ setNameError("A view with this name already exists");
979
+ return;
980
+ }
981
+ if (onSaveView) {
982
+ onSaveView({
983
+ name: trimmedName,
984
+ columnVisibility: currentState.columnVisibility,
985
+ columnOrder: currentState.columnOrder,
986
+ filters: currentState.filters,
987
+ sorting: currentState.sorting,
988
+ isDefault: setAsDefault
989
+ });
990
+ }
991
+ setNewViewName("");
992
+ setSetAsDefault(false);
993
+ setNameError(null);
994
+ setSaveDialogOpen(false);
995
+ };
996
+ const handleUpdateCurrentView = () => {
997
+ if (!activeViewId || !onUpdateView) return;
998
+ onUpdateView(activeViewId, {
999
+ columnVisibility: currentState.columnVisibility,
1000
+ columnOrder: currentState.columnOrder,
1001
+ filters: currentState.filters,
1002
+ sorting: currentState.sorting,
1003
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1004
+ });
1005
+ };
1006
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1007
+ /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-1", className), children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1008
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1009
+ Button,
1010
+ {
1011
+ ...dataTableTopperButtonProps,
1012
+ className: cn(
1013
+ fontSizeClass,
1014
+ dataTableTopperOpenStateClasses,
1015
+ dataTableTopperResponsiveClasses
1016
+ ),
1017
+ children: [
1018
+ /* @__PURE__ */ jsx(LayoutGrid, { className: "size-4" }),
1019
+ /* @__PURE__ */ jsx("span", { className: "hidden @min-[450px]:inline", children: activeView?.name ?? "Default View" })
1020
+ ]
1021
+ }
1022
+ ) }),
1023
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", className: "w-56", children: [
1024
+ views.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1025
+ views.map((view) => /* @__PURE__ */ jsxs(
1026
+ "div",
1027
+ {
1028
+ className: "group relative flex items-center",
1029
+ children: [
1030
+ /* @__PURE__ */ jsxs(
1031
+ DropdownMenuItem,
1032
+ {
1033
+ onClick: () => onSelectView(view),
1034
+ className: cn(
1035
+ "flex-1 flex items-center justify-between pr-16",
1036
+ fontSizeClass
1037
+ ),
1038
+ children: [
1039
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
1040
+ view.isDefault && /* @__PURE__ */ jsx(Star, { className: "size-3 fill-yellow-400 text-yellow-400" }),
1041
+ /* @__PURE__ */ jsx("span", { children: view.name })
1042
+ ] }),
1043
+ activeViewId === view.id && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" })
1044
+ ]
1045
+ }
1046
+ ),
1047
+ /* @__PURE__ */ jsxs("div", { className: "absolute right-2 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
1048
+ !view.isDefault && onSetDefaultView && /* @__PURE__ */ jsx(
1049
+ "button",
1050
+ {
1051
+ type: "button",
1052
+ onClick: (e) => {
1053
+ e.stopPropagation();
1054
+ onSetDefaultView(view.id);
1055
+ },
1056
+ className: "p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground",
1057
+ title: "Set as default",
1058
+ children: /* @__PURE__ */ jsx(Star, { className: "size-3" })
1059
+ }
1060
+ ),
1061
+ views.length > 1 && onDeleteView && /* @__PURE__ */ jsx(
1062
+ "button",
1063
+ {
1064
+ type: "button",
1065
+ onClick: (e) => {
1066
+ e.stopPropagation();
1067
+ onDeleteView(view.id);
1068
+ },
1069
+ className: "p-1 rounded hover:bg-accent text-muted-foreground hover:text-destructive",
1070
+ title: "Delete view",
1071
+ children: /* @__PURE__ */ jsx(Trash2, { className: "size-3" })
1072
+ }
1073
+ )
1074
+ ] })
1075
+ ]
1076
+ },
1077
+ view.id
1078
+ )),
1079
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {})
1080
+ ] }) : null,
1081
+ onUpdateView && hasChanges && activeView && /* @__PURE__ */ jsxs(
1082
+ DropdownMenuItem,
1083
+ {
1084
+ onClick: handleUpdateCurrentView,
1085
+ className: fontSizeClass,
1086
+ children: [
1087
+ /* @__PURE__ */ jsx(Save, { className: "mr-2 size-3.5" }),
1088
+ "Save changes"
1089
+ ]
1090
+ }
1091
+ ),
1092
+ onSaveView && /* @__PURE__ */ jsxs(
1093
+ DropdownMenuItem,
1094
+ {
1095
+ onClick: () => setSaveDialogOpen(true),
1096
+ className: fontSizeClass,
1097
+ children: [
1098
+ /* @__PURE__ */ jsx(Plus, { className: "mr-2 size-3.5" }),
1099
+ "Save as new view"
1100
+ ]
1101
+ }
1102
+ )
1103
+ ] })
1104
+ ] }) }),
1105
+ /* @__PURE__ */ jsx(
1106
+ Dialog,
1107
+ {
1108
+ open: saveDialogOpen,
1109
+ onOpenChange: (open) => {
1110
+ setSaveDialogOpen(open);
1111
+ if (!open) {
1112
+ setNewViewName("");
1113
+ setSetAsDefault(false);
1114
+ setNameError(null);
1115
+ }
1116
+ },
1117
+ children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
1118
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
1119
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Save View" }),
1120
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Save your current table configuration as a reusable view." })
1121
+ ] }),
1122
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4 py-4", children: [
1123
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1124
+ /* @__PURE__ */ jsx(Label, { htmlFor: "view-name", children: "View name" }),
1125
+ /* @__PURE__ */ jsx(
1126
+ Input,
1127
+ {
1128
+ id: "view-name",
1129
+ placeholder: "e.g., Active Users, Recent Signups",
1130
+ value: newViewName,
1131
+ onChange: (e) => {
1132
+ setNewViewName(e.target.value);
1133
+ checkDuplicateName(e.target.value);
1134
+ },
1135
+ onKeyDown: (e) => {
1136
+ if (e.key === "Enter") handleSaveNewView();
1137
+ },
1138
+ className: nameError ? "border-destructive" : "",
1139
+ autoFocus: true
1140
+ }
1141
+ ),
1142
+ nameError && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: nameError })
1143
+ ] }),
1144
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1145
+ /* @__PURE__ */ jsx(
1146
+ "input",
1147
+ {
1148
+ type: "checkbox",
1149
+ id: "set-default",
1150
+ checked: setAsDefault,
1151
+ onChange: (e) => setSetAsDefault(e.target.checked),
1152
+ className: "size-4 rounded border-muted-foreground/30"
1153
+ }
1154
+ ),
1155
+ /* @__PURE__ */ jsx(
1156
+ Label,
1157
+ {
1158
+ htmlFor: "set-default",
1159
+ className: "text-sm font-normal cursor-pointer",
1160
+ children: "Set as default view"
1161
+ }
1162
+ )
1163
+ ] })
1164
+ ] }),
1165
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
1166
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setSaveDialogOpen(false), children: "Cancel" }),
1167
+ /* @__PURE__ */ jsx(
1168
+ Button,
1169
+ {
1170
+ onClick: handleSaveNewView,
1171
+ disabled: !newViewName.trim() || !!nameError,
1172
+ children: "Save View"
1173
+ }
1174
+ )
1175
+ ] })
1176
+ ] })
1177
+ }
1178
+ )
1179
+ ] });
1180
+ }
1181
+
1182
+ // src/blocks/table/config.ts
1183
+ var dataTableConfig = {
1184
+ textOperators: [
1185
+ { label: "Contains", value: "iLike" },
1186
+ { label: "Does not contain", value: "notILike" },
1187
+ { label: "Is", value: "eq" },
1188
+ { label: "Is not", value: "ne" },
1189
+ { label: "Is empty", value: "isEmpty" },
1190
+ { label: "Is not empty", value: "isNotEmpty" }
1191
+ ],
1192
+ numericOperators: [
1193
+ { label: "Is", value: "eq" },
1194
+ { label: "Is not", value: "ne" },
1195
+ { label: "Is less than", value: "lt" },
1196
+ { label: "Is less than or equal to", value: "lte" },
1197
+ { label: "Is greater than", value: "gt" },
1198
+ { label: "Is greater than or equal to", value: "gte" },
1199
+ { label: "Is between", value: "isBetween" },
1200
+ { label: "Is empty", value: "isEmpty" },
1201
+ { label: "Is not empty", value: "isNotEmpty" }
1202
+ ],
1203
+ dateOperators: [
1204
+ { label: "Is", value: "eq" },
1205
+ { label: "Is not", value: "ne" },
1206
+ { label: "Is before", value: "lt" },
1207
+ { label: "Is after", value: "gt" },
1208
+ { label: "Is on or before", value: "lte" },
1209
+ { label: "Is on or after", value: "gte" },
1210
+ { label: "Is between", value: "isBetween" },
1211
+ { label: "Is relative to today", value: "isRelativeToToday" },
1212
+ { label: "Is empty", value: "isEmpty" },
1213
+ { label: "Is not empty", value: "isNotEmpty" }
1214
+ ],
1215
+ selectOperators: [
1216
+ { label: "Is", value: "eq" },
1217
+ { label: "Is not", value: "ne" },
1218
+ { label: "Is empty", value: "isEmpty" },
1219
+ { label: "Is not empty", value: "isNotEmpty" }
1220
+ ],
1221
+ multiSelectOperators: [
1222
+ { label: "Has any of", value: "inArray" },
1223
+ { label: "Has none of", value: "notInArray" },
1224
+ { label: "Is empty", value: "isEmpty" },
1225
+ { label: "Is not empty", value: "isNotEmpty" }
1226
+ ],
1227
+ booleanOperators: [
1228
+ { label: "Is", value: "eq" },
1229
+ { label: "Is not", value: "ne" }
1230
+ ],
1231
+ sortOrders: [
1232
+ { label: "Asc", value: "asc" },
1233
+ { label: "Desc", value: "desc" }
1234
+ ],
1235
+ filterVariants: [
1236
+ "text",
1237
+ "number",
1238
+ "range",
1239
+ "date",
1240
+ "dateRange",
1241
+ "boolean",
1242
+ "select",
1243
+ "multiSelect"
1244
+ ],
1245
+ operators: [
1246
+ "iLike",
1247
+ "notILike",
1248
+ "eq",
1249
+ "ne",
1250
+ "inArray",
1251
+ "notInArray",
1252
+ "isEmpty",
1253
+ "isNotEmpty",
1254
+ "lt",
1255
+ "lte",
1256
+ "gt",
1257
+ "gte",
1258
+ "isBetween",
1259
+ "isRelativeToToday"
1260
+ ],
1261
+ joinOperators: ["and", "or"]
1262
+ };
1263
+ function DataTablePagination({
1264
+ table,
1265
+ pageSizeOptions = [10, 20, 30, 40, 50],
1266
+ className,
1267
+ ...props
1268
+ }) {
1269
+ return /* @__PURE__ */ jsxs(
1270
+ "div",
1271
+ {
1272
+ className: cn(
1273
+ "flex w-full flex-col-reverse items-center justify-between gap-4 overflow-auto p-1 sm:flex-row sm:gap-8",
1274
+ className
1275
+ ),
1276
+ ...props,
1277
+ children: [
1278
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 whitespace-nowrap text-muted-foreground text-sm", children: [
1279
+ table.getFilteredSelectedRowModel().rows.length,
1280
+ " of",
1281
+ " ",
1282
+ table.getFilteredRowModel().rows.length,
1283
+ " row(s) selected."
1284
+ ] }),
1285
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col-reverse items-center gap-4 sm:flex-row sm:gap-6 lg:gap-8", children: [
1286
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
1287
+ /* @__PURE__ */ jsx("p", { className: "whitespace-nowrap font-medium text-sm", children: "Rows per page" }),
1288
+ /* @__PURE__ */ jsxs(
1289
+ Select,
1290
+ {
1291
+ value: `${table.getState().pagination.pageSize}`,
1292
+ onValueChange: (value) => {
1293
+ table.setPageSize(Number(value));
1294
+ },
1295
+ children: [
1296
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 w-18 data-size:h-8", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: table.getState().pagination.pageSize }) }),
1297
+ /* @__PURE__ */ jsx(SelectContent, { side: "top", children: /* @__PURE__ */ jsx(SelectGroup, { children: pageSizeOptions.map((pageSize) => /* @__PURE__ */ jsx(SelectItem, { value: `${pageSize}`, children: pageSize }, pageSize)) }) })
1298
+ ]
1299
+ }
1300
+ )
1301
+ ] }),
1302
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center font-medium text-sm", children: [
1303
+ "Page ",
1304
+ table.getState().pagination.pageIndex + 1,
1305
+ " of",
1306
+ " ",
1307
+ table.getPageCount()
1308
+ ] }),
1309
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
1310
+ /* @__PURE__ */ jsx(
1311
+ Button,
1312
+ {
1313
+ "aria-label": "Go to first page",
1314
+ variant: "outline",
1315
+ size: "icon",
1316
+ className: "hidden size-8 lg:flex",
1317
+ onClick: () => table.setPageIndex(0),
1318
+ disabled: !table.getCanPreviousPage(),
1319
+ children: /* @__PURE__ */ jsx(ChevronsLeft, {})
1320
+ }
1321
+ ),
1322
+ /* @__PURE__ */ jsx(
1323
+ Button,
1324
+ {
1325
+ "aria-label": "Go to previous page",
1326
+ variant: "outline",
1327
+ size: "icon",
1328
+ className: "size-8",
1329
+ onClick: () => table.previousPage(),
1330
+ disabled: !table.getCanPreviousPage(),
1331
+ children: /* @__PURE__ */ jsx(ChevronLeft, {})
1332
+ }
1333
+ ),
1334
+ /* @__PURE__ */ jsx(
1335
+ Button,
1336
+ {
1337
+ "aria-label": "Go to next page",
1338
+ variant: "outline",
1339
+ size: "icon",
1340
+ className: "size-8",
1341
+ onClick: () => table.nextPage(),
1342
+ disabled: !table.getCanNextPage(),
1343
+ children: /* @__PURE__ */ jsx(ChevronRight, {})
1344
+ }
1345
+ ),
1346
+ /* @__PURE__ */ jsx(
1347
+ Button,
1348
+ {
1349
+ "aria-label": "Go to last page",
1350
+ variant: "outline",
1351
+ size: "icon",
1352
+ className: "hidden size-8 lg:flex",
1353
+ onClick: () => table.setPageIndex(table.getPageCount() - 1),
1354
+ disabled: !table.getCanNextPage(),
1355
+ children: /* @__PURE__ */ jsx(ChevronsRight, {})
1356
+ }
1357
+ )
1358
+ ] })
1359
+ ] })
1360
+ ]
1361
+ }
1362
+ );
1363
+ }
1364
+
1365
+ // src/blocks/table/lib/data-table.ts
1366
+ function getColumnPinningStyle({
1367
+ column,
1368
+ withBorder = false
1369
+ }) {
1370
+ const isPinned = column.getIsPinned();
1371
+ const isLastLeftPinnedColumn = isPinned === "left" && column.getIsLastColumn("left");
1372
+ const isFirstRightPinnedColumn = isPinned === "right" && column.getIsFirstColumn("right");
1373
+ return {
1374
+ boxShadow: withBorder ? isLastLeftPinnedColumn ? "-4px 0 4px -4px var(--border) inset" : isFirstRightPinnedColumn ? "4px 0 4px -4px var(--border) inset" : void 0 : void 0,
1375
+ left: isPinned === "left" ? `${column.getStart("left")}px` : void 0,
1376
+ right: isPinned === "right" ? `${column.getAfter("right")}px` : void 0,
1377
+ opacity: isPinned ? 0.97 : 1,
1378
+ position: isPinned ? "sticky" : "relative",
1379
+ background: isPinned ? "var(--background)" : "var(--background)",
1380
+ width: column.getSize(),
1381
+ zIndex: isPinned ? 1 : void 0
1382
+ };
1383
+ }
1384
+ function getFilterOperators(filterVariant) {
1385
+ const operatorMap = {
1386
+ text: dataTableConfig.textOperators,
1387
+ number: dataTableConfig.numericOperators,
1388
+ range: dataTableConfig.numericOperators,
1389
+ date: dataTableConfig.dateOperators,
1390
+ dateRange: dataTableConfig.dateOperators,
1391
+ boolean: dataTableConfig.booleanOperators,
1392
+ select: dataTableConfig.selectOperators,
1393
+ multiSelect: dataTableConfig.multiSelectOperators
1394
+ };
1395
+ return operatorMap[filterVariant] ?? dataTableConfig.textOperators;
1396
+ }
1397
+ function getDefaultFilterOperator(filterVariant) {
1398
+ const operators = getFilterOperators(filterVariant);
1399
+ return operators[0]?.value ?? (filterVariant === "text" ? "iLike" : "eq");
1400
+ }
1401
+ function getValidFilters(filters) {
1402
+ return filters.filter(
1403
+ (filter) => filter.operator === "isEmpty" || filter.operator === "isNotEmpty" || (Array.isArray(filter.value) ? filter.value.length > 0 : filter.value !== "" && filter.value !== null && filter.value !== void 0)
1404
+ );
1405
+ }
1406
+ function DataTable({
1407
+ table,
1408
+ actionBar,
1409
+ footer,
1410
+ onRowClick,
1411
+ getRowClassName,
1412
+ children,
1413
+ className,
1414
+ ...props
1415
+ }) {
1416
+ return /* @__PURE__ */ jsxs(
1417
+ "div",
1418
+ {
1419
+ className: cn("flex w-full flex-col gap-2.5 overflow-auto", className),
1420
+ ...props,
1421
+ children: [
1422
+ children,
1423
+ /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
1424
+ /* @__PURE__ */ jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx(
1425
+ TableHead,
1426
+ {
1427
+ colSpan: header.colSpan,
1428
+ style: {
1429
+ ...getColumnPinningStyle({ column: header.column })
1430
+ },
1431
+ children: header.isPlaceholder ? null : flexRender(
1432
+ header.column.columnDef.header,
1433
+ header.getContext()
1434
+ )
1435
+ },
1436
+ header.id
1437
+ )) }, headerGroup.id)) }),
1438
+ /* @__PURE__ */ jsx(TableBody, { children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx(
1439
+ TableRow,
1440
+ {
1441
+ "data-state": row.getIsSelected() && "selected",
1442
+ className: cn(
1443
+ onRowClick && "cursor-pointer",
1444
+ getRowClassName?.(row)
1445
+ ),
1446
+ onClick: onRowClick ? () => onRowClick(row) : void 0,
1447
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(
1448
+ TableCell,
1449
+ {
1450
+ style: {
1451
+ ...getColumnPinningStyle({ column: cell.column })
1452
+ },
1453
+ children: flexRender(
1454
+ cell.column.columnDef.cell,
1455
+ cell.getContext()
1456
+ )
1457
+ },
1458
+ cell.id
1459
+ ))
1460
+ },
1461
+ row.id
1462
+ )) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(
1463
+ TableCell,
1464
+ {
1465
+ colSpan: table.getAllColumns().length,
1466
+ className: "h-24 text-center",
1467
+ children: "No results."
1468
+ }
1469
+ ) }) }),
1470
+ footer ? /* @__PURE__ */ jsx(TableFooter, { children: footer }) : null
1471
+ ] }) }),
1472
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2.5", children: [
1473
+ /* @__PURE__ */ jsx(DataTablePagination, { table }),
1474
+ actionBar && table.getFilteredSelectedRowModel().rows.length > 0 && actionBar
1475
+ ] })
1476
+ ]
1477
+ }
1478
+ );
1479
+ }
1480
+ function DataTableColumnHeader({
1481
+ column,
1482
+ label,
1483
+ className,
1484
+ ...props
1485
+ }) {
1486
+ if (!column.getCanSort() && !column.getCanHide()) {
1487
+ return /* @__PURE__ */ jsx("div", { className: cn(className), children: label });
1488
+ }
1489
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1490
+ /* @__PURE__ */ jsxs(
1491
+ DropdownMenuTrigger,
1492
+ {
1493
+ className: cn(
1494
+ "-ml-1.5 flex h-8 items-center gap-1.5 rounded-md px-2 py-1.5 hover:bg-accent focus:outline-none focus:ring-1 focus:ring-ring data-[state=open]:bg-accent [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground",
1495
+ className
1496
+ ),
1497
+ ...props,
1498
+ children: [
1499
+ label,
1500
+ column.getCanSort() && (column.getIsSorted() === "desc" ? /* @__PURE__ */ jsx(ChevronDown, {}) : column.getIsSorted() === "asc" ? /* @__PURE__ */ jsx(ChevronUp, {}) : /* @__PURE__ */ jsx(ChevronsUpDown, {}))
1501
+ ]
1502
+ }
1503
+ ),
1504
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", className: "w-28", children: [
1505
+ column.getCanSort() && /* @__PURE__ */ jsxs(Fragment, { children: [
1506
+ /* @__PURE__ */ jsxs(
1507
+ DropdownMenuCheckboxItem,
1508
+ {
1509
+ className: "relative pr-8 pl-2 [&>span:first-child]:right-2 [&>span:first-child]:left-auto [&_svg]:text-muted-foreground",
1510
+ checked: column.getIsSorted() === "asc",
1511
+ onClick: () => column.toggleSorting(false),
1512
+ children: [
1513
+ /* @__PURE__ */ jsx(ChevronUp, {}),
1514
+ "Asc"
1515
+ ]
1516
+ }
1517
+ ),
1518
+ /* @__PURE__ */ jsxs(
1519
+ DropdownMenuCheckboxItem,
1520
+ {
1521
+ className: "relative pr-8 pl-2 [&>span:first-child]:right-2 [&>span:first-child]:left-auto [&_svg]:text-muted-foreground",
1522
+ checked: column.getIsSorted() === "desc",
1523
+ onClick: () => column.toggleSorting(true),
1524
+ children: [
1525
+ /* @__PURE__ */ jsx(ChevronDown, {}),
1526
+ "Desc"
1527
+ ]
1528
+ }
1529
+ ),
1530
+ column.getIsSorted() && /* @__PURE__ */ jsxs(
1531
+ DropdownMenuItem,
1532
+ {
1533
+ className: "pl-2 [&_svg]:text-muted-foreground",
1534
+ onClick: () => column.clearSorting(),
1535
+ children: [
1536
+ /* @__PURE__ */ jsx(X, {}),
1537
+ "Reset"
1538
+ ]
1539
+ }
1540
+ )
1541
+ ] }),
1542
+ column.getCanHide() && /* @__PURE__ */ jsxs(
1543
+ DropdownMenuCheckboxItem,
1544
+ {
1545
+ className: "relative pr-8 pl-2 [&>span:first-child]:right-2 [&>span:first-child]:left-auto [&_svg]:text-muted-foreground",
1546
+ checked: !column.getIsVisible(),
1547
+ onClick: () => column.toggleVisibility(false),
1548
+ children: [
1549
+ /* @__PURE__ */ jsx(EyeOff, {}),
1550
+ "Hide"
1551
+ ]
1552
+ }
1553
+ )
1554
+ ] })
1555
+ ] });
1556
+ }
1557
+
1558
+ // src/blocks/table/lib/format.ts
1559
+ function formatDate2(date, opts = {}) {
1560
+ if (!date) return "";
1561
+ try {
1562
+ return new Intl.DateTimeFormat("en-US", {
1563
+ month: opts.month ?? "long",
1564
+ day: opts.day ?? "numeric",
1565
+ year: opts.year ?? "numeric",
1566
+ ...opts
1567
+ }).format(new Date(date));
1568
+ } catch (_err) {
1569
+ return "";
1570
+ }
1571
+ }
1572
+ function getIsDateRange(value) {
1573
+ return value && typeof value === "object" && !Array.isArray(value);
1574
+ }
1575
+ function parseAsDate(timestamp) {
1576
+ if (!timestamp) return void 0;
1577
+ const numericTimestamp = typeof timestamp === "string" ? Number(timestamp) : timestamp;
1578
+ const date = new Date(numericTimestamp);
1579
+ return !Number.isNaN(date.getTime()) ? date : void 0;
1580
+ }
1581
+ function parseColumnFilterValue(value) {
1582
+ if (value === null || value === void 0) {
1583
+ return [];
1584
+ }
1585
+ if (Array.isArray(value)) {
1586
+ return value.map((item) => {
1587
+ if (typeof item === "number" || typeof item === "string") {
1588
+ return item;
1589
+ }
1590
+ return void 0;
1591
+ });
1592
+ }
1593
+ if (typeof value === "string" || typeof value === "number") {
1594
+ return [value];
1595
+ }
1596
+ return [];
1597
+ }
1598
+ function DataTableDateFilter({
1599
+ column,
1600
+ title,
1601
+ multiple
1602
+ }) {
1603
+ const columnFilterValue = column.getFilterValue();
1604
+ const selectedDates = React12.useMemo(() => {
1605
+ if (!columnFilterValue) {
1606
+ return multiple ? { from: void 0, to: void 0 } : [];
1607
+ }
1608
+ if (multiple) {
1609
+ const timestamps2 = parseColumnFilterValue(columnFilterValue);
1610
+ return {
1611
+ from: parseAsDate(timestamps2[0]),
1612
+ to: parseAsDate(timestamps2[1])
1613
+ };
1614
+ }
1615
+ const timestamps = parseColumnFilterValue(columnFilterValue);
1616
+ const date = parseAsDate(timestamps[0]);
1617
+ return date ? [date] : [];
1618
+ }, [columnFilterValue, multiple]);
1619
+ const onSelect = React12.useCallback(
1620
+ (date) => {
1621
+ if (!date) {
1622
+ column.setFilterValue(void 0);
1623
+ return;
1624
+ }
1625
+ if (multiple && !("getTime" in date)) {
1626
+ const from = date.from?.getTime();
1627
+ const to = date.to?.getTime();
1628
+ column.setFilterValue(from || to ? [from, to] : void 0);
1629
+ } else if (!multiple && "getTime" in date) {
1630
+ column.setFilterValue(date.getTime());
1631
+ }
1632
+ },
1633
+ [column, multiple]
1634
+ );
1635
+ const onReset = React12.useCallback(
1636
+ (event) => {
1637
+ event.stopPropagation();
1638
+ column.setFilterValue(void 0);
1639
+ },
1640
+ [column]
1641
+ );
1642
+ const hasValue = React12.useMemo(() => {
1643
+ if (multiple) {
1644
+ if (!getIsDateRange(selectedDates)) return false;
1645
+ return selectedDates.from || selectedDates.to;
1646
+ }
1647
+ if (!Array.isArray(selectedDates)) return false;
1648
+ return selectedDates.length > 0;
1649
+ }, [multiple, selectedDates]);
1650
+ const formatDateRange = React12.useCallback((range) => {
1651
+ if (!range.from && !range.to) return "";
1652
+ if (range.from && range.to) {
1653
+ return `${formatDate2(range.from)} - ${formatDate2(range.to)}`;
1654
+ }
1655
+ return formatDate2(range.from ?? range.to);
1656
+ }, []);
1657
+ const label = React12.useMemo(() => {
1658
+ if (multiple) {
1659
+ if (!getIsDateRange(selectedDates)) return null;
1660
+ const hasSelectedDates = selectedDates.from || selectedDates.to;
1661
+ const dateText2 = hasSelectedDates ? formatDateRange(selectedDates) : "Select date range";
1662
+ return /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
1663
+ /* @__PURE__ */ jsx("span", { children: title }),
1664
+ hasSelectedDates && /* @__PURE__ */ jsxs(Fragment, { children: [
1665
+ /* @__PURE__ */ jsx(
1666
+ Separator,
1667
+ {
1668
+ orientation: "vertical",
1669
+ className: "mx-0.5 data-[orientation=vertical]:h-4"
1670
+ }
1671
+ ),
1672
+ /* @__PURE__ */ jsx("span", { children: dateText2 })
1673
+ ] })
1674
+ ] });
1675
+ }
1676
+ if (getIsDateRange(selectedDates)) return null;
1677
+ const hasSelectedDate = selectedDates.length > 0;
1678
+ const dateText = hasSelectedDate ? formatDate2(selectedDates[0]) : "Select date";
1679
+ return /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
1680
+ /* @__PURE__ */ jsx("span", { children: title }),
1681
+ hasSelectedDate && /* @__PURE__ */ jsxs(Fragment, { children: [
1682
+ /* @__PURE__ */ jsx(
1683
+ Separator,
1684
+ {
1685
+ orientation: "vertical",
1686
+ className: "mx-0.5 data-[orientation=vertical]:h-4"
1687
+ }
1688
+ ),
1689
+ /* @__PURE__ */ jsx("span", { children: dateText })
1690
+ ] })
1691
+ ] });
1692
+ }, [selectedDates, multiple, formatDateRange, title]);
1693
+ return /* @__PURE__ */ jsxs(Popover, { children: [
1694
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outline", className: "border-dashed font-normal", children: [
1695
+ hasValue ? /* @__PURE__ */ jsx(
1696
+ "div",
1697
+ {
1698
+ role: "button",
1699
+ "aria-label": `Clear ${title} filter`,
1700
+ tabIndex: 0,
1701
+ onClick: onReset,
1702
+ className: "rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
1703
+ children: /* @__PURE__ */ jsx(XCircle, {})
1704
+ }
1705
+ ) : /* @__PURE__ */ jsx(CalendarIcon, {}),
1706
+ label
1707
+ ] }) }),
1708
+ /* @__PURE__ */ jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: multiple ? /* @__PURE__ */ jsx(
1709
+ Calendar,
1710
+ {
1711
+ autoFocus: true,
1712
+ captionLayout: "dropdown",
1713
+ mode: "range",
1714
+ selected: getIsDateRange(selectedDates) ? selectedDates : { from: void 0, to: void 0 },
1715
+ onSelect
1716
+ }
1717
+ ) : /* @__PURE__ */ jsx(
1718
+ Calendar,
1719
+ {
1720
+ captionLayout: "dropdown",
1721
+ mode: "single",
1722
+ selected: !getIsDateRange(selectedDates) ? selectedDates[0] : void 0,
1723
+ onSelect
1724
+ }
1725
+ ) })
1726
+ ] });
1727
+ }
1728
+ function DataTableFacetedFilter({
1729
+ column,
1730
+ title,
1731
+ options,
1732
+ multiple
1733
+ }) {
1734
+ const [open, setOpen] = React12.useState(false);
1735
+ const columnFilterValue = column?.getFilterValue();
1736
+ const selectedValues = new Set(
1737
+ Array.isArray(columnFilterValue) ? columnFilterValue : []
1738
+ );
1739
+ const onItemSelect = React12.useCallback(
1740
+ (option, isSelected) => {
1741
+ if (!column) return;
1742
+ if (multiple) {
1743
+ const newSelectedValues = new Set(selectedValues);
1744
+ if (isSelected) {
1745
+ newSelectedValues.delete(option.value);
1746
+ } else {
1747
+ newSelectedValues.add(option.value);
1748
+ }
1749
+ const filterValues = Array.from(newSelectedValues);
1750
+ column.setFilterValue(filterValues.length ? filterValues : void 0);
1751
+ } else {
1752
+ column.setFilterValue(isSelected ? void 0 : [option.value]);
1753
+ setOpen(false);
1754
+ }
1755
+ },
1756
+ [column, multiple, selectedValues]
1757
+ );
1758
+ const onReset = React12.useCallback(
1759
+ (event) => {
1760
+ event?.stopPropagation();
1761
+ column?.setFilterValue(void 0);
1762
+ },
1763
+ [column]
1764
+ );
1765
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
1766
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outline", className: "border-dashed font-normal", children: [
1767
+ selectedValues?.size > 0 ? /* @__PURE__ */ jsx(
1768
+ "div",
1769
+ {
1770
+ role: "button",
1771
+ "aria-label": `Clear ${title} filter`,
1772
+ tabIndex: 0,
1773
+ className: "rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
1774
+ onClick: onReset,
1775
+ children: /* @__PURE__ */ jsx(XCircle, {})
1776
+ }
1777
+ ) : /* @__PURE__ */ jsx(PlusCircle, {}),
1778
+ title,
1779
+ selectedValues?.size > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1780
+ /* @__PURE__ */ jsx(
1781
+ Separator,
1782
+ {
1783
+ orientation: "vertical",
1784
+ className: "mx-0.5 data-[orientation=vertical]:h-4"
1785
+ }
1786
+ ),
1787
+ /* @__PURE__ */ jsx(
1788
+ Badge,
1789
+ {
1790
+ variant: "secondary",
1791
+ className: "rounded-sm px-1 font-normal lg:hidden",
1792
+ children: selectedValues.size
1793
+ }
1794
+ ),
1795
+ /* @__PURE__ */ jsx("div", { className: "hidden items-center gap-1 lg:flex", children: selectedValues.size > 2 ? /* @__PURE__ */ jsxs(
1796
+ Badge,
1797
+ {
1798
+ variant: "secondary",
1799
+ className: "rounded-sm px-1 font-normal",
1800
+ children: [
1801
+ selectedValues.size,
1802
+ " selected"
1803
+ ]
1804
+ }
1805
+ ) : options.filter((option) => selectedValues.has(option.value)).map((option) => /* @__PURE__ */ jsx(
1806
+ Badge,
1807
+ {
1808
+ variant: "secondary",
1809
+ className: "rounded-sm px-1 font-normal",
1810
+ children: option.label
1811
+ },
1812
+ option.value
1813
+ )) })
1814
+ ] })
1815
+ ] }) }),
1816
+ /* @__PURE__ */ jsx(PopoverContent, { className: "w-50 p-0", align: "start", children: /* @__PURE__ */ jsxs(Command, { children: [
1817
+ /* @__PURE__ */ jsx(CommandInput, { placeholder: title }),
1818
+ /* @__PURE__ */ jsxs(CommandList, { className: "max-h-full", children: [
1819
+ /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
1820
+ /* @__PURE__ */ jsx(CommandGroup, { className: "max-h-[300px] scroll-py-1 overflow-y-auto overflow-x-hidden", children: options.map((option) => {
1821
+ const isSelected = selectedValues.has(option.value);
1822
+ return /* @__PURE__ */ jsxs(
1823
+ CommandItem,
1824
+ {
1825
+ className: "[&>svg:last-child]:hidden",
1826
+ onSelect: () => onItemSelect(option, isSelected),
1827
+ children: [
1828
+ /* @__PURE__ */ jsx(
1829
+ "div",
1830
+ {
1831
+ className: cn(
1832
+ "flex size-4 items-center justify-center rounded-sm border border-primary",
1833
+ isSelected ? "bg-primary text-primary-foreground" : "opacity-50 [&_svg]:invisible"
1834
+ ),
1835
+ children: /* @__PURE__ */ jsx(Check, {})
1836
+ }
1837
+ ),
1838
+ option.icon && /* @__PURE__ */ jsx(option.icon, {}),
1839
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: option.label }),
1840
+ option.count && /* @__PURE__ */ jsx("span", { className: "ml-auto font-mono text-xs", children: option.count })
1841
+ ]
1842
+ },
1843
+ option.value
1844
+ );
1845
+ }) }),
1846
+ selectedValues.size > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1847
+ /* @__PURE__ */ jsx(CommandSeparator, {}),
1848
+ /* @__PURE__ */ jsx(CommandGroup, { children: /* @__PURE__ */ jsx(
1849
+ CommandItem,
1850
+ {
1851
+ onSelect: () => onReset(),
1852
+ className: "justify-center text-center",
1853
+ children: "Clear filters"
1854
+ }
1855
+ ) })
1856
+ ] })
1857
+ ] })
1858
+ ] }) })
1859
+ ] });
1860
+ }
1861
+ function DataTableSkeleton({
1862
+ columnCount,
1863
+ rowCount = 10,
1864
+ filterCount = 0,
1865
+ cellWidths = ["auto"],
1866
+ withViewOptions = true,
1867
+ withPagination = true,
1868
+ shrinkZero = false,
1869
+ className,
1870
+ ...props
1871
+ }) {
1872
+ const cozyCellWidths = Array.from(
1873
+ { length: columnCount },
1874
+ (_, index) => cellWidths[index % cellWidths.length] ?? "auto"
1875
+ );
1876
+ return /* @__PURE__ */ jsxs(
1877
+ "div",
1878
+ {
1879
+ className: cn("flex w-full flex-col gap-2.5 overflow-auto", className),
1880
+ ...props,
1881
+ children: [
1882
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between gap-2 overflow-auto p-1", children: [
1883
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center gap-2", children: filterCount > 0 ? Array.from({ length: filterCount }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-18 border-dashed" }, i)) : null }),
1884
+ withViewOptions ? /* @__PURE__ */ jsx(Skeleton, { className: "ml-auto hidden h-7 w-18 lg:flex" }) : null
1885
+ ] }),
1886
+ /* @__PURE__ */ jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
1887
+ /* @__PURE__ */ jsx(TableHeader, { children: Array.from({ length: 1 }).map((_, i) => /* @__PURE__ */ jsx(TableRow, { className: "hover:bg-transparent", children: Array.from({ length: columnCount }).map((_2, j) => /* @__PURE__ */ jsx(
1888
+ TableHead,
1889
+ {
1890
+ style: {
1891
+ width: cozyCellWidths[j],
1892
+ minWidth: shrinkZero ? cozyCellWidths[j] : "auto"
1893
+ },
1894
+ children: /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-full" })
1895
+ },
1896
+ j
1897
+ )) }, i)) }),
1898
+ /* @__PURE__ */ jsx(TableBody, { children: Array.from({ length: rowCount }).map((_, i) => /* @__PURE__ */ jsx(TableRow, { className: "hover:bg-transparent", children: Array.from({ length: columnCount }).map((_2, j) => /* @__PURE__ */ jsx(
1899
+ TableCell,
1900
+ {
1901
+ style: {
1902
+ width: cozyCellWidths[j],
1903
+ minWidth: shrinkZero ? cozyCellWidths[j] : "auto"
1904
+ },
1905
+ children: /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-full" })
1906
+ },
1907
+ j
1908
+ )) }, i)) })
1909
+ ] }) }),
1910
+ withPagination ? /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between gap-4 overflow-auto p-1 sm:gap-8", children: [
1911
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-40 shrink-0" }),
1912
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 sm:gap-6 lg:gap-8", children: [
1913
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1914
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-24" }),
1915
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-18" })
1916
+ ] }),
1917
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center font-medium text-sm", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-20" }) }),
1918
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1919
+ /* @__PURE__ */ jsx(Skeleton, { className: "hidden size-7 lg:block" }),
1920
+ /* @__PURE__ */ jsx(Skeleton, { className: "size-7" }),
1921
+ /* @__PURE__ */ jsx(Skeleton, { className: "size-7" }),
1922
+ /* @__PURE__ */ jsx(Skeleton, { className: "hidden size-7 lg:block" })
1923
+ ] })
1924
+ ] })
1925
+ ] }) : null
1926
+ ]
1927
+ }
1928
+ );
1929
+ }
1930
+ function Slider({
1931
+ className,
1932
+ defaultValue,
1933
+ value,
1934
+ min = 0,
1935
+ max = 100,
1936
+ ...props
1937
+ }) {
1938
+ const _values = React12.useMemo(
1939
+ () => Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max],
1940
+ [value, defaultValue, min, max]
1941
+ );
1942
+ return /* @__PURE__ */ jsxs(
1943
+ SliderPrimitive.Root,
1944
+ {
1945
+ "data-slot": "slider",
1946
+ defaultValue,
1947
+ value,
1948
+ min,
1949
+ max,
1950
+ className: cn(
1951
+ "relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
1952
+ className
1953
+ ),
1954
+ ...props,
1955
+ children: [
1956
+ /* @__PURE__ */ jsx(
1957
+ SliderPrimitive.Track,
1958
+ {
1959
+ "data-slot": "slider-track",
1960
+ className: cn(
1961
+ "relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
1962
+ ),
1963
+ children: /* @__PURE__ */ jsx(
1964
+ SliderPrimitive.Range,
1965
+ {
1966
+ "data-slot": "slider-range",
1967
+ className: cn(
1968
+ "absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
1969
+ )
1970
+ }
1971
+ )
1972
+ }
1973
+ ),
1974
+ Array.from({ length: _values.length }, (_, index) => /* @__PURE__ */ jsx(
1975
+ SliderPrimitive.Thumb,
1976
+ {
1977
+ "data-slot": "slider-thumb",
1978
+ className: "block size-4 shrink-0 rounded-full border border-primary bg-white shadow-sm ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
1979
+ },
1980
+ index
1981
+ ))
1982
+ ]
1983
+ }
1984
+ );
1985
+ }
1986
+ function getIsValidRange(value) {
1987
+ return Array.isArray(value) && value.length === 2 && typeof value[0] === "number" && typeof value[1] === "number";
1988
+ }
1989
+ function parseValuesAsNumbers(value) {
1990
+ if (Array.isArray(value) && value.length === 2 && value.every(
1991
+ (v) => (typeof v === "string" || typeof v === "number") && !Number.isNaN(v)
1992
+ )) {
1993
+ return [Number(value[0]), Number(value[1])];
1994
+ }
1995
+ return void 0;
1996
+ }
1997
+ function DataTableSliderFilter({
1998
+ column,
1999
+ title
2000
+ }) {
2001
+ const id = React12.useId();
2002
+ const columnFilterValue = parseValuesAsNumbers(column.getFilterValue());
2003
+ const defaultRange = column.columnDef.meta?.range;
2004
+ const unit = column.columnDef.meta?.unit;
2005
+ const { min, max, step } = React12.useMemo(() => {
2006
+ let minValue = 0;
2007
+ let maxValue = 100;
2008
+ if (defaultRange && getIsValidRange(defaultRange)) {
2009
+ [minValue, maxValue] = defaultRange;
2010
+ } else {
2011
+ const values = column.getFacetedMinMaxValues();
2012
+ if (values && Array.isArray(values) && values.length === 2) {
2013
+ const [facetMinValue, facetMaxValue] = values;
2014
+ if (typeof facetMinValue === "number" && typeof facetMaxValue === "number") {
2015
+ minValue = facetMinValue;
2016
+ maxValue = facetMaxValue;
2017
+ }
2018
+ }
2019
+ }
2020
+ const rangeSize = maxValue - minValue;
2021
+ const step2 = rangeSize <= 20 ? 1 : rangeSize <= 100 ? Math.ceil(rangeSize / 20) : Math.ceil(rangeSize / 50);
2022
+ return { min: minValue, max: maxValue, step: step2 };
2023
+ }, [column, defaultRange]);
2024
+ const range = React12.useMemo(() => {
2025
+ return columnFilterValue ?? [min, max];
2026
+ }, [columnFilterValue, min, max]);
2027
+ const formatValue = React12.useCallback((value) => {
2028
+ return value.toLocaleString(void 0, { maximumFractionDigits: 0 });
2029
+ }, []);
2030
+ const onFromInputChange = React12.useCallback(
2031
+ (event) => {
2032
+ const numValue = Number(event.target.value);
2033
+ if (!Number.isNaN(numValue) && numValue >= min && numValue <= range[1]) {
2034
+ column.setFilterValue([numValue, range[1]]);
2035
+ }
2036
+ },
2037
+ [column, min, range]
2038
+ );
2039
+ const onToInputChange = React12.useCallback(
2040
+ (event) => {
2041
+ const numValue = Number(event.target.value);
2042
+ if (!Number.isNaN(numValue) && numValue <= max && numValue >= range[0]) {
2043
+ column.setFilterValue([range[0], numValue]);
2044
+ }
2045
+ },
2046
+ [column, max, range]
2047
+ );
2048
+ const onSliderValueChange = React12.useCallback(
2049
+ (value) => {
2050
+ if (Array.isArray(value) && value.length === 2) {
2051
+ column.setFilterValue(value);
2052
+ }
2053
+ },
2054
+ [column]
2055
+ );
2056
+ const onReset = React12.useCallback(
2057
+ (event) => {
2058
+ if (event.target instanceof HTMLDivElement) {
2059
+ event.stopPropagation();
2060
+ }
2061
+ column.setFilterValue(void 0);
2062
+ },
2063
+ [column]
2064
+ );
2065
+ return /* @__PURE__ */ jsxs(Popover, { children: [
2066
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outline", className: "border-dashed font-normal", children: [
2067
+ columnFilterValue ? /* @__PURE__ */ jsx(
2068
+ "div",
2069
+ {
2070
+ role: "button",
2071
+ "aria-label": `Clear ${title} filter`,
2072
+ tabIndex: 0,
2073
+ className: "rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
2074
+ onClick: onReset,
2075
+ children: /* @__PURE__ */ jsx(XCircle, {})
2076
+ }
2077
+ ) : /* @__PURE__ */ jsx(PlusCircle, {}),
2078
+ /* @__PURE__ */ jsx("span", { children: title }),
2079
+ columnFilterValue ? /* @__PURE__ */ jsxs(Fragment, { children: [
2080
+ /* @__PURE__ */ jsx(
2081
+ Separator,
2082
+ {
2083
+ orientation: "vertical",
2084
+ className: "mx-0.5 data-[orientation=vertical]:h-4"
2085
+ }
2086
+ ),
2087
+ formatValue(columnFilterValue[0]),
2088
+ " -",
2089
+ " ",
2090
+ formatValue(columnFilterValue[1]),
2091
+ unit ? ` ${unit}` : ""
2092
+ ] }) : null
2093
+ ] }) }),
2094
+ /* @__PURE__ */ jsxs(PopoverContent, { align: "start", className: "flex w-auto flex-col gap-4", children: [
2095
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
2096
+ /* @__PURE__ */ jsx("p", { className: "font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", children: title }),
2097
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
2098
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-from`, className: "sr-only", children: "From" }),
2099
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2100
+ /* @__PURE__ */ jsx(
2101
+ Input,
2102
+ {
2103
+ id: `${id}-from`,
2104
+ type: "number",
2105
+ "aria-valuemin": min,
2106
+ "aria-valuemax": max,
2107
+ inputMode: "numeric",
2108
+ pattern: "[0-9]*",
2109
+ placeholder: min.toString(),
2110
+ min,
2111
+ max,
2112
+ value: range[0]?.toString(),
2113
+ onChange: onFromInputChange,
2114
+ className: cn("h-8 w-24", unit && "pr-8")
2115
+ }
2116
+ ),
2117
+ unit && /* @__PURE__ */ jsx("span", { className: "absolute top-0 right-0 bottom-0 flex items-center rounded-r-md bg-accent px-2 text-muted-foreground text-sm", children: unit })
2118
+ ] }),
2119
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-to`, className: "sr-only", children: "to" }),
2120
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2121
+ /* @__PURE__ */ jsx(
2122
+ Input,
2123
+ {
2124
+ id: `${id}-to`,
2125
+ type: "number",
2126
+ "aria-valuemin": min,
2127
+ "aria-valuemax": max,
2128
+ inputMode: "numeric",
2129
+ pattern: "[0-9]*",
2130
+ placeholder: max.toString(),
2131
+ min,
2132
+ max,
2133
+ value: range[1]?.toString(),
2134
+ onChange: onToInputChange,
2135
+ className: cn("h-8 w-24", unit && "pr-8")
2136
+ }
2137
+ ),
2138
+ unit && /* @__PURE__ */ jsx("span", { className: "absolute top-0 right-0 bottom-0 flex items-center rounded-r-md bg-accent px-2 text-muted-foreground text-sm", children: unit })
2139
+ ] })
2140
+ ] }),
2141
+ /* @__PURE__ */ jsxs(Label, { htmlFor: `${id}-slider`, className: "sr-only", children: [
2142
+ title,
2143
+ " slider"
2144
+ ] }),
2145
+ /* @__PURE__ */ jsx(
2146
+ Slider,
2147
+ {
2148
+ id: `${id}-slider`,
2149
+ min,
2150
+ max,
2151
+ step,
2152
+ value: range,
2153
+ onValueChange: onSliderValueChange
2154
+ }
2155
+ )
2156
+ ] }),
2157
+ /* @__PURE__ */ jsx(
2158
+ Button,
2159
+ {
2160
+ "aria-label": `Clear ${title} filter`,
2161
+ variant: "outline",
2162
+ onClick: onReset,
2163
+ children: "Clear"
2164
+ }
2165
+ )
2166
+ ] })
2167
+ ] });
2168
+ }
2169
+ function DataTableViewOptions({
2170
+ table,
2171
+ disabled,
2172
+ className,
2173
+ ...props
2174
+ }) {
2175
+ const columns = React12.useMemo(
2176
+ () => table.getAllColumns().filter(
2177
+ (column) => typeof column.accessorFn !== "undefined" && column.getCanHide()
2178
+ ),
2179
+ [table]
2180
+ );
2181
+ return /* @__PURE__ */ jsxs(Popover, { children: [
2182
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
2183
+ Button,
2184
+ {
2185
+ "aria-label": "Toggle columns",
2186
+ role: "combobox",
2187
+ variant: "outline",
2188
+ className: "ml-auto hidden h-8 font-normal lg:flex",
2189
+ disabled,
2190
+ children: [
2191
+ /* @__PURE__ */ jsx(Settings2, { className: "text-muted-foreground" }),
2192
+ "View"
2193
+ ]
2194
+ }
2195
+ ) }),
2196
+ /* @__PURE__ */ jsx(PopoverContent, { className: cn("w-44 p-0", className), ...props, children: /* @__PURE__ */ jsxs(Command, { children: [
2197
+ /* @__PURE__ */ jsx(CommandInput, { placeholder: "Search columns..." }),
2198
+ /* @__PURE__ */ jsxs(CommandList, { children: [
2199
+ /* @__PURE__ */ jsx(CommandEmpty, { children: "No columns found." }),
2200
+ /* @__PURE__ */ jsx(CommandGroup, { children: columns.map((column) => /* @__PURE__ */ jsx(
2201
+ CommandItem,
2202
+ {
2203
+ "data-checked": column.getIsVisible(),
2204
+ onSelect: () => column.toggleVisibility(!column.getIsVisible()),
2205
+ children: /* @__PURE__ */ jsx("span", { className: "truncate", children: column.columnDef.meta?.label ?? column.id })
2206
+ },
2207
+ column.id
2208
+ )) })
2209
+ ] })
2210
+ ] }) })
2211
+ ] });
2212
+ }
2213
+ function DataTableToolbar({
2214
+ table,
2215
+ children,
2216
+ className,
2217
+ ...props
2218
+ }) {
2219
+ const isFiltered = table.getState().columnFilters.length > 0;
2220
+ const columns = React12.useMemo(
2221
+ () => table.getAllColumns().filter((column) => column.getCanFilter()),
2222
+ [table]
2223
+ );
2224
+ const onReset = React12.useCallback(() => {
2225
+ table.resetColumnFilters();
2226
+ }, [table]);
2227
+ return /* @__PURE__ */ jsxs(
2228
+ "div",
2229
+ {
2230
+ role: "toolbar",
2231
+ "aria-orientation": "horizontal",
2232
+ className: cn(
2233
+ "flex w-full items-start justify-between gap-2 p-1",
2234
+ className
2235
+ ),
2236
+ ...props,
2237
+ children: [
2238
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-2", children: [
2239
+ columns.map((column) => /* @__PURE__ */ jsx(DataTableToolbarFilter, { column }, column.id)),
2240
+ isFiltered && /* @__PURE__ */ jsxs(
2241
+ Button,
2242
+ {
2243
+ "aria-label": "Reset filters",
2244
+ variant: "outline",
2245
+ className: "border-dashed",
2246
+ onClick: onReset,
2247
+ children: [
2248
+ /* @__PURE__ */ jsx(X, {}),
2249
+ "Reset"
2250
+ ]
2251
+ }
2252
+ )
2253
+ ] }),
2254
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2255
+ children,
2256
+ /* @__PURE__ */ jsx(DataTableViewOptions, { table, align: "end" })
2257
+ ] })
2258
+ ]
2259
+ }
2260
+ );
2261
+ }
2262
+ function DataTableToolbarFilter({
2263
+ column
2264
+ }) {
2265
+ {
2266
+ const columnMeta = column.columnDef.meta;
2267
+ const onFilterRender = React12.useCallback(() => {
2268
+ if (!columnMeta?.variant) return null;
2269
+ switch (columnMeta.variant) {
2270
+ case "text":
2271
+ return /* @__PURE__ */ jsx(
2272
+ Input,
2273
+ {
2274
+ placeholder: columnMeta.placeholder ?? columnMeta.label,
2275
+ value: column.getFilterValue() ?? "",
2276
+ onChange: (event) => column.setFilterValue(event.target.value),
2277
+ className: "h-8 w-40 lg:w-56"
2278
+ }
2279
+ );
2280
+ case "number":
2281
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2282
+ /* @__PURE__ */ jsx(
2283
+ Input,
2284
+ {
2285
+ type: "number",
2286
+ inputMode: "numeric",
2287
+ placeholder: columnMeta.placeholder ?? columnMeta.label,
2288
+ value: column.getFilterValue() ?? "",
2289
+ onChange: (event) => column.setFilterValue(event.target.value),
2290
+ className: cn("h-8 w-[120px]", columnMeta.unit && "pr-8")
2291
+ }
2292
+ ),
2293
+ columnMeta.unit && /* @__PURE__ */ jsx("span", { className: "absolute top-0 right-0 bottom-0 flex items-center rounded-r-md bg-accent px-2 text-muted-foreground text-sm", children: columnMeta.unit })
2294
+ ] });
2295
+ case "range":
2296
+ return /* @__PURE__ */ jsx(
2297
+ DataTableSliderFilter,
2298
+ {
2299
+ column,
2300
+ title: columnMeta.label ?? column.id
2301
+ }
2302
+ );
2303
+ case "date":
2304
+ case "dateRange":
2305
+ return /* @__PURE__ */ jsx(
2306
+ DataTableDateFilter,
2307
+ {
2308
+ column,
2309
+ title: columnMeta.label ?? column.id,
2310
+ multiple: columnMeta.variant === "dateRange"
2311
+ }
2312
+ );
2313
+ case "select":
2314
+ case "multiSelect":
2315
+ return /* @__PURE__ */ jsx(
2316
+ DataTableFacetedFilter,
2317
+ {
2318
+ column,
2319
+ title: columnMeta.label ?? column.id,
2320
+ options: columnMeta.options ?? [],
2321
+ multiple: columnMeta.variant === "multiSelect"
2322
+ }
2323
+ );
2324
+ default:
2325
+ return null;
2326
+ }
2327
+ }, [column, columnMeta]);
2328
+ return onFilterRender();
2329
+ }
2330
+ }
2331
+ var sortingItemSchema = z.object({
2332
+ id: z.string(),
2333
+ desc: z.boolean()
2334
+ });
2335
+ var getSortingStateParser = (columnIds) => {
2336
+ const validKeys = columnIds ? columnIds instanceof Set ? columnIds : new Set(columnIds) : null;
2337
+ return createParser({
2338
+ parse: (value) => {
2339
+ try {
2340
+ const parsed = JSON.parse(value);
2341
+ const result = z.array(sortingItemSchema).safeParse(parsed);
2342
+ if (!result.success) return null;
2343
+ if (validKeys && result.data.some((item) => !validKeys.has(item.id))) {
2344
+ return null;
2345
+ }
2346
+ return result.data;
2347
+ } catch {
2348
+ return null;
2349
+ }
2350
+ },
2351
+ serialize: (value) => JSON.stringify(value),
2352
+ eq: (a, b) => a.length === b.length && a.every(
2353
+ (item, index) => item.id === b[index]?.id && item.desc === b[index]?.desc
2354
+ )
2355
+ });
2356
+ };
2357
+ var filterItemSchema = z.object({
2358
+ id: z.string(),
2359
+ value: z.union([z.string(), z.array(z.string())]),
2360
+ variant: z.enum(dataTableConfig.filterVariants),
2361
+ operator: z.enum(dataTableConfig.operators),
2362
+ filterId: z.string()
2363
+ });
2364
+ var getFiltersStateParser = (columnIds) => {
2365
+ const validKeys = columnIds ? columnIds instanceof Set ? columnIds : new Set(columnIds) : null;
2366
+ return createParser({
2367
+ parse: (value) => {
2368
+ try {
2369
+ const parsed = JSON.parse(value);
2370
+ const result = z.array(filterItemSchema).safeParse(parsed);
2371
+ if (!result.success) return null;
2372
+ if (validKeys && result.data.some((item) => !validKeys.has(item.id))) {
2373
+ return null;
2374
+ }
2375
+ return result.data;
2376
+ } catch {
2377
+ return null;
2378
+ }
2379
+ },
2380
+ serialize: (value) => JSON.stringify(value),
2381
+ eq: (a, b) => a.length === b.length && a.every(
2382
+ (filter, index) => filter.id === b[index]?.id && filter.value === b[index]?.value && filter.variant === b[index]?.variant && filter.operator === b[index]?.operator
2383
+ )
2384
+ });
2385
+ };
2386
+ var PAGE_KEY = "page";
2387
+ var PER_PAGE_KEY = "perPage";
2388
+ var SORT_KEY = "sort";
2389
+ var FILTERS_KEY = "filters";
2390
+ var JOIN_OPERATOR_KEY = "joinOperator";
2391
+ var ARRAY_SEPARATOR = ",";
2392
+ var DEBOUNCE_MS = 300;
2393
+ var THROTTLE_MS = 50;
2394
+ function useDataTable(props) {
2395
+ const {
2396
+ columns,
2397
+ pageCount = -1,
2398
+ initialState,
2399
+ queryKeys,
2400
+ history = "replace",
2401
+ debounceMs = DEBOUNCE_MS,
2402
+ throttleMs = THROTTLE_MS,
2403
+ clearOnDefault = false,
2404
+ enableAdvancedFilter = false,
2405
+ scroll = false,
2406
+ shallow = true,
2407
+ startTransition,
2408
+ ...tableProps
2409
+ } = props;
2410
+ const pageKey = queryKeys?.page ?? PAGE_KEY;
2411
+ const perPageKey = queryKeys?.perPage ?? PER_PAGE_KEY;
2412
+ const sortKey = queryKeys?.sort ?? SORT_KEY;
2413
+ const filtersKey = queryKeys?.filters ?? FILTERS_KEY;
2414
+ const joinOperatorKey = queryKeys?.joinOperator ?? JOIN_OPERATOR_KEY;
2415
+ const queryStateOptions = React12.useMemo(
2416
+ () => ({
2417
+ history,
2418
+ scroll,
2419
+ shallow,
2420
+ throttleMs,
2421
+ debounceMs,
2422
+ clearOnDefault,
2423
+ startTransition
2424
+ }),
2425
+ [
2426
+ history,
2427
+ scroll,
2428
+ shallow,
2429
+ throttleMs,
2430
+ debounceMs,
2431
+ clearOnDefault,
2432
+ startTransition
2433
+ ]
2434
+ );
2435
+ const [rowSelection, setRowSelection] = React12.useState(
2436
+ initialState?.rowSelection ?? {}
2437
+ );
2438
+ const [columnVisibility, setColumnVisibility] = React12.useState(initialState?.columnVisibility ?? {});
2439
+ const [page, setPage] = useQueryState(
2440
+ pageKey,
2441
+ parseAsInteger.withOptions(queryStateOptions).withDefault(1)
2442
+ );
2443
+ const [perPage, setPerPage] = useQueryState(
2444
+ perPageKey,
2445
+ parseAsInteger.withOptions(queryStateOptions).withDefault(initialState?.pagination?.pageSize ?? 10)
2446
+ );
2447
+ const pagination = React12.useMemo(() => {
2448
+ return {
2449
+ pageIndex: page - 1,
2450
+ // zero-based index -> one-based index
2451
+ pageSize: perPage
2452
+ };
2453
+ }, [page, perPage]);
2454
+ const onPaginationChange = React12.useCallback(
2455
+ (updaterOrValue) => {
2456
+ if (typeof updaterOrValue === "function") {
2457
+ const newPagination = updaterOrValue(pagination);
2458
+ void setPage(newPagination.pageIndex + 1);
2459
+ void setPerPage(newPagination.pageSize);
2460
+ } else {
2461
+ void setPage(updaterOrValue.pageIndex + 1);
2462
+ void setPerPage(updaterOrValue.pageSize);
2463
+ }
2464
+ },
2465
+ [pagination, setPage, setPerPage]
2466
+ );
2467
+ const columnIds = React12.useMemo(() => {
2468
+ return new Set(
2469
+ columns.map((column) => column.id).filter(Boolean)
2470
+ );
2471
+ }, [columns]);
2472
+ const [sorting, setSorting] = useQueryState(
2473
+ sortKey,
2474
+ getSortingStateParser(columnIds).withOptions(queryStateOptions).withDefault(initialState?.sorting ?? [])
2475
+ );
2476
+ const onSortingChange = React12.useCallback(
2477
+ (updaterOrValue) => {
2478
+ if (typeof updaterOrValue === "function") {
2479
+ const newSorting = updaterOrValue(sorting);
2480
+ setSorting(newSorting);
2481
+ } else {
2482
+ setSorting(updaterOrValue);
2483
+ }
2484
+ },
2485
+ [sorting, setSorting]
2486
+ );
2487
+ const filterableColumns = React12.useMemo(() => {
2488
+ if (enableAdvancedFilter) return [];
2489
+ return columns.filter((column) => column.enableColumnFilter);
2490
+ }, [columns, enableAdvancedFilter]);
2491
+ const filterParsers = React12.useMemo(() => {
2492
+ if (enableAdvancedFilter) return {};
2493
+ return filterableColumns.reduce((acc, column) => {
2494
+ if (column.meta?.options) {
2495
+ acc[column.id ?? ""] = parseAsArrayOf(
2496
+ parseAsString,
2497
+ ARRAY_SEPARATOR
2498
+ ).withOptions(queryStateOptions);
2499
+ } else {
2500
+ acc[column.id ?? ""] = parseAsString.withOptions(queryStateOptions);
2501
+ }
2502
+ return acc;
2503
+ }, {});
2504
+ }, [filterableColumns, queryStateOptions, enableAdvancedFilter]);
2505
+ const [filterValues, setFilterValues] = useQueryStates(filterParsers);
2506
+ const debouncedSetFilterValues = useDebouncedCallback(
2507
+ (values) => {
2508
+ void setPage(1);
2509
+ void setFilterValues(values);
2510
+ },
2511
+ debounceMs
2512
+ );
2513
+ const initialColumnFilters = React12.useMemo(() => {
2514
+ if (enableAdvancedFilter) return [];
2515
+ return Object.entries(filterValues).reduce(
2516
+ (filters, [key, value]) => {
2517
+ if (value !== null) {
2518
+ const processedValue = Array.isArray(value) ? value : typeof value === "string" && /[^a-zA-Z0-9]/.test(value) ? value.split(/[^a-zA-Z0-9]+/).filter(Boolean) : [value];
2519
+ filters.push({
2520
+ id: key,
2521
+ value: processedValue
2522
+ });
2523
+ }
2524
+ return filters;
2525
+ },
2526
+ []
2527
+ );
2528
+ }, [filterValues, enableAdvancedFilter]);
2529
+ const [columnFilters, setColumnFilters] = React12.useState(initialColumnFilters);
2530
+ const onColumnFiltersChange = React12.useCallback(
2531
+ (updaterOrValue) => {
2532
+ if (enableAdvancedFilter) return;
2533
+ setColumnFilters((prev) => {
2534
+ const next = typeof updaterOrValue === "function" ? updaterOrValue(prev) : updaterOrValue;
2535
+ const filterUpdates = next.reduce((acc, filter) => {
2536
+ if (filterableColumns.find((column) => column.id === filter.id)) {
2537
+ acc[filter.id] = filter.value;
2538
+ }
2539
+ return acc;
2540
+ }, {});
2541
+ for (const prevFilter of prev) {
2542
+ if (!next.some((filter) => filter.id === prevFilter.id)) {
2543
+ filterUpdates[prevFilter.id] = null;
2544
+ }
2545
+ }
2546
+ debouncedSetFilterValues(filterUpdates);
2547
+ return next;
2548
+ });
2549
+ },
2550
+ [debouncedSetFilterValues, filterableColumns, enableAdvancedFilter]
2551
+ );
2552
+ const table = useReactTable({
2553
+ ...tableProps,
2554
+ columns,
2555
+ initialState,
2556
+ pageCount,
2557
+ state: {
2558
+ pagination,
2559
+ sorting,
2560
+ columnVisibility,
2561
+ rowSelection,
2562
+ columnFilters
2563
+ },
2564
+ defaultColumn: {
2565
+ ...tableProps.defaultColumn,
2566
+ enableColumnFilter: false
2567
+ },
2568
+ enableRowSelection: true,
2569
+ onRowSelectionChange: setRowSelection,
2570
+ onPaginationChange,
2571
+ onSortingChange,
2572
+ onColumnFiltersChange,
2573
+ onColumnVisibilityChange: setColumnVisibility,
2574
+ getCoreRowModel: getCoreRowModel(),
2575
+ getFilteredRowModel: getFilteredRowModel(),
2576
+ getPaginationRowModel: getPaginationRowModel(),
2577
+ getSortedRowModel: getSortedRowModel(),
2578
+ getFacetedRowModel: getFacetedRowModel(),
2579
+ getFacetedUniqueValues: getFacetedUniqueValues(),
2580
+ getFacetedMinMaxValues: getFacetedMinMaxValues(),
2581
+ manualPagination: true,
2582
+ manualSorting: true,
2583
+ manualFiltering: true,
2584
+ meta: {
2585
+ ...tableProps.meta,
2586
+ queryKeys: {
2587
+ page: pageKey,
2588
+ perPage: perPageKey,
2589
+ sort: sortKey,
2590
+ filters: filtersKey,
2591
+ joinOperator: joinOperatorKey
2592
+ }
2593
+ }
2594
+ });
2595
+ return React12.useMemo(
2596
+ () => ({ table, shallow, debounceMs, throttleMs }),
2597
+ [table, shallow, debounceMs, throttleMs]
2598
+ );
2599
+ }
2600
+
2601
+ export { DataTable, DataTableAddButton, DataTableColumnHeader, DataTableDateFilter, DataTableExportButton, DataTableFacetedFilter, DataTablePagination, DataTableRowActions, DataTableSearch, DataTableSkeleton, DataTableSliderFilter, DataTableSummary, DataTableToolbar, DataTableTopper, DataTableViewOptions, DataTableViews, IconButton, Slider, dataTableConfig, exportToCsv, exportToExcel, getColumnPinningStyle, getDefaultFilterOperator, getFilterOperators, getFiltersStateParser, getSortingStateParser, getValidFilters, iconButtonVariants, useDataTable };