@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.
- package/README.md +1 -1
- package/dist/blog.js +8 -6
- package/dist/blog.mjs +3 -1
- package/dist/charts.d.cts +1 -1
- package/dist/charts.d.ts +1 -1
- package/dist/{chunk-6DVWMJ3H.mjs → chunk-2EFVMX6V.mjs} +4 -3
- package/dist/chunk-33JR5SYE.js +1 -0
- package/dist/{chunk-OZZWDIOY.js → chunk-375DECW4.js} +32 -31
- package/dist/chunk-3NDB4YPC.js +1 -0
- package/dist/{chunk-PZRI43EZ.js → chunk-46JYKBRX.js} +0 -43
- package/dist/chunk-5D55OVD5.js +75 -0
- package/dist/chunk-5RW4PYZ6.js +1 -0
- package/dist/chunk-5THF4YP6.mjs +1 -0
- package/dist/{chunk-JORVSG52.js → chunk-663CFAHS.js} +212 -269
- package/dist/chunk-6BUBNZPG.mjs +1 -0
- package/dist/chunk-6HKJDV43.mjs +48 -0
- package/dist/chunk-6NCRGHV3.mjs +64 -0
- package/dist/{chunk-OLAAXLXY.mjs → chunk-6QAKQG57.mjs} +5 -4
- package/dist/chunk-72JGQ7IJ.mjs +1 -0
- package/dist/{chunk-N6AFNFZR.mjs → chunk-7ERVZXIN.mjs} +215 -270
- package/dist/chunk-7IKHZKAC.js +1 -0
- package/dist/chunk-APFEP5B7.mjs +100 -0
- package/dist/chunk-C3OADNSG.js +348 -0
- package/dist/{chunk-RVEFPVZF.mjs → chunk-C57MX3BG.mjs} +1 -0
- package/dist/{chunk-CC4KUIKC.js → chunk-DH5Z3ETN.js} +67 -45
- package/dist/chunk-DYWZ23QT.mjs +90 -0
- package/dist/{chunk-KRRIRS6A.mjs → chunk-E67IR6HU.mjs} +31 -9
- package/dist/{chunk-D3QXPL47.mjs → chunk-EXQSWHLD.mjs} +7 -6
- package/dist/{chunk-ZOA7B32D.js → chunk-F35KL6TX.js} +10 -9
- package/dist/{chunk-YSLD2HLP.mjs → chunk-FFJC66KO.mjs} +2 -1
- package/dist/chunk-FRRS2YZH.mjs +1 -0
- package/dist/chunk-G5TQWWQA.mjs +1 -0
- package/dist/{chunk-MPZFPU4X.js → chunk-GMBLPQ3I.js} +4 -3
- package/dist/chunk-IJFPPLQW.js +50 -0
- package/dist/chunk-J6OLBSZR.js +1 -0
- package/dist/chunk-KGGQ5NZV.js +1 -0
- package/dist/chunk-KHCC5UKW.mjs +1 -0
- package/dist/{chunk-BMFQG6RA.mjs → chunk-KJIX6V32.mjs} +108 -1885
- package/dist/chunk-LABHD4PU.js +109 -0
- package/dist/chunk-LQCVRWVF.js +1 -0
- package/dist/{chunk-GAIQJCAZ.js → chunk-LT5VD4KR.js} +150 -1953
- package/dist/{chunk-7DHKQODW.mjs → chunk-LTLCIRZY.mjs} +257 -474
- package/dist/chunk-N5BHXWR3.mjs +34 -0
- package/dist/chunk-OCO3Z5YA.js +37 -0
- package/dist/chunk-OFQLWSUR.mjs +1 -0
- package/dist/chunk-OIJ7XMDV.mjs +71 -0
- package/dist/chunk-ORBH4IBC.mjs +316 -0
- package/dist/{chunk-C4UT5V3P.js → chunk-OWHI5VGJ.js} +1 -0
- package/dist/chunk-OWWOAYIY.js +2652 -0
- package/dist/chunk-PFHOXDSW.mjs +10 -0
- package/dist/chunk-Q52ZEL62.mjs +1 -0
- package/dist/chunk-QRS7DJGS.js +103 -0
- package/dist/chunk-R26Y7LGJ.js +1 -0
- package/dist/{chunk-BFWX5GJZ.mjs → chunk-R3X4B4JJ.mjs} +56 -8
- package/dist/chunk-RBUYW6QQ.js +1 -0
- package/dist/chunk-RM7ACPTM.mjs +2601 -0
- package/dist/chunk-RODSGPBB.mjs +75 -0
- package/dist/chunk-SORWLKOK.js +1 -0
- package/dist/{chunk-T6ZBA6VJ.js → chunk-UHAV34YX.js} +9 -8
- package/dist/{chunk-GUSTCU2W.mjs → chunk-ULANYJ7Y.mjs} +1 -59
- package/dist/chunk-ULDE7QSN.js +70 -0
- package/dist/chunk-UT36VNVZ.mjs +47 -0
- package/dist/chunk-UY3H4PKB.js +71 -0
- package/dist/{chunk-KB7UXIQZ.mjs → chunk-VIVWFQG5.mjs} +3 -1
- package/dist/{chunk-ESZ7CBA2.js → chunk-VKBJ3SGT.js} +7 -5
- package/dist/{chunk-UM7WMXIU.js → chunk-W3YOQ5ZD.js} +265 -505
- package/dist/chunk-WOITB4JL.js +1 -0
- package/dist/{chunk-E42B4GSB.js → chunk-XGJL6DLV.js} +58 -7
- package/dist/chunk-YKZEKJMZ.mjs +1 -0
- package/dist/chunk-YRIBFIQ5.js +116 -0
- package/dist/chunk-ZFLZA7UP.mjs +1 -0
- package/dist/chunk-ZKUIUE7W.mjs +1 -0
- package/dist/chunk-ZWWJ3RRA.js +15 -0
- package/dist/data-grid.d.cts +241 -0
- package/dist/data-grid.d.ts +241 -0
- package/dist/data-grid.js +6486 -0
- package/dist/data-grid.mjs +6459 -0
- package/dist/data-table-CDQBo-Ve.d.ts +818 -0
- package/dist/data-table-jLzt6plY.d.cts +818 -0
- package/dist/data-table.d.cts +8 -42
- package/dist/data-table.d.ts +8 -42
- package/dist/data-table.js +61 -187
- package/dist/data-table.mjs +11 -5
- package/dist/finance.d.cts +534 -0
- package/dist/finance.d.ts +534 -0
- package/dist/finance.js +188 -0
- package/dist/finance.mjs +15 -0
- package/dist/forms.js +9 -6
- package/dist/forms.mjs +7 -4
- package/dist/{hooks-B2jU1GVT.d.ts → hooks-A55E0fgf.d.ts} +3 -2
- package/dist/{hooks-8ORd7T1A.d.cts → hooks-Bys_AZPI.d.cts} +3 -2
- package/dist/hooks.d.cts +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +26 -23
- package/dist/hooks.mjs +6 -3
- package/dist/index.d.cts +536 -665
- package/dist/index.d.ts +536 -665
- package/dist/index.js +3830 -3408
- package/dist/index.mjs +2068 -1767
- package/dist/layouts.js +26 -25
- package/dist/layouts.mjs +5 -4
- package/dist/marketing-3d.js +1 -0
- package/dist/marketing-3d.mjs +1 -0
- package/dist/marketing.js +75 -74
- package/dist/marketing.mjs +5 -4
- package/dist/media.js +1 -0
- package/dist/media.mjs +1 -0
- package/dist/navigation.js +29 -28
- package/dist/navigation.mjs +7 -6
- package/dist/primitives.d.cts +72 -109
- package/dist/primitives.d.ts +72 -109
- package/dist/primitives.js +78 -72
- package/dist/primitives.mjs +8 -6
- package/dist/settings.js +9 -9
- package/dist/settings.mjs +4 -4
- package/package.json +21 -4
- package/dist/UnifiedTableControls-CG299y9h.d.ts +0 -1233
- package/dist/UnifiedTableControls-CIjRpNhy.d.cts +0 -1233
- package/dist/chunk-GMBGWOCR.mjs +0 -48
- package/dist/chunk-HBLKVQIQ.mjs +0 -23
- package/dist/chunk-HMAMMC72.js +0 -26
- package/dist/chunk-MVYRNJA6.js +0 -74
|
@@ -1,25 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
"use client";
|
|
2
|
+
import { getUnitDivisor } from './chunk-LTLCIRZY.mjs';
|
|
3
|
+
import { dataTableTopperButtonProps, dataTableTopperOpenStateClasses } from './chunk-PFHOXDSW.mjs';
|
|
4
|
+
import { Calendar as Calendar$1, Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator } from './chunk-ORBH4IBC.mjs';
|
|
5
|
+
import { Popover, PopoverTrigger, PopoverContent } from './chunk-RODSGPBB.mjs';
|
|
4
6
|
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from './chunk-6BUBNZPG.mjs';
|
|
7
|
+
import { Button } from './chunk-VBD4Q5LL.mjs';
|
|
5
8
|
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter } from './chunk-FRRS2YZH.mjs';
|
|
6
|
-
import {
|
|
7
|
-
import { buttonVariants, Button } from './chunk-VBD4Q5LL.mjs';
|
|
8
|
-
import { DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem } from './chunk-OFQLWSUR.mjs';
|
|
9
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuItem, DropdownMenuSeparator } from './chunk-OFQLWSUR.mjs';
|
|
9
10
|
import { Tooltip, TooltipTrigger, TooltipContent } from './chunk-YKZEKJMZ.mjs';
|
|
10
|
-
import { Input } from './chunk-STEP6C4C.mjs';
|
|
11
11
|
import { cn } from './chunk-IMKLN273.mjs';
|
|
12
|
+
import * as SwitchPrimitive from '@radix-ui/react-switch';
|
|
12
13
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
13
|
-
import { ChevronLeft, ChevronRight, Calendar
|
|
14
|
-
import
|
|
15
|
-
import * as React12 from 'react';
|
|
14
|
+
import { ChevronLeft, ChevronRight, Calendar, Percent, Check, Minus, Plus, Settings, ChevronsUpDown, MoreHorizontal, Filter, CalendarDays, Building2, MapPin, Download, FileText, FileSpreadsheet, Settings2, BarChart3, ChevronUp, ChevronDown, SlidersHorizontal, PieChartIcon, ChartColumn } from 'lucide-react';
|
|
15
|
+
import * as React5 from 'react';
|
|
16
16
|
import { useState, useRef, useMemo, useEffect, useCallback, Fragment as Fragment$1 } from 'react';
|
|
17
17
|
import { format, parseISO, isValid, endOfMonth, startOfMonth, addMonths, subDays, addYears } from 'date-fns';
|
|
18
|
-
import { cva } from 'class-variance-authority';
|
|
19
|
-
import { formatDate } from '@caffeinebounce/shared-utils';
|
|
20
|
-
import { Command as Command$1 } from 'cmdk';
|
|
21
18
|
import { ResponsiveContainer, ComposedChart, CartesianGrid, XAxis, YAxis, ReferenceLine, Tooltip as Tooltip$1, Line, Bar, Area, AreaChart, BarChart, PieChart, Pie, Cell, Legend, Sector } from 'recharts';
|
|
22
19
|
|
|
20
|
+
function Switch({
|
|
21
|
+
className,
|
|
22
|
+
size = "default",
|
|
23
|
+
...props
|
|
24
|
+
}) {
|
|
25
|
+
return /* @__PURE__ */ jsx(
|
|
26
|
+
SwitchPrimitive.Root,
|
|
27
|
+
{
|
|
28
|
+
"data-slot": "switch",
|
|
29
|
+
"data-size": size,
|
|
30
|
+
className: cn(
|
|
31
|
+
"peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80",
|
|
32
|
+
className
|
|
33
|
+
),
|
|
34
|
+
...props,
|
|
35
|
+
children: /* @__PURE__ */ jsx(
|
|
36
|
+
SwitchPrimitive.Thumb,
|
|
37
|
+
{
|
|
38
|
+
"data-slot": "switch-thumb",
|
|
39
|
+
className: cn(
|
|
40
|
+
"pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground"
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
23
47
|
function ChartTooltipShell({
|
|
24
48
|
children,
|
|
25
49
|
className
|
|
@@ -67,62 +91,6 @@ function ChartTooltipRow({
|
|
|
67
91
|
)
|
|
68
92
|
] });
|
|
69
93
|
}
|
|
70
|
-
function Calendar({
|
|
71
|
-
className,
|
|
72
|
-
classNames,
|
|
73
|
-
showOutsideDays = true,
|
|
74
|
-
captionLayout = "dropdown",
|
|
75
|
-
...props
|
|
76
|
-
}) {
|
|
77
|
-
return /* @__PURE__ */ jsx(
|
|
78
|
-
DayPicker,
|
|
79
|
-
{
|
|
80
|
-
showOutsideDays,
|
|
81
|
-
captionLayout,
|
|
82
|
-
className: cn("p-3", className),
|
|
83
|
-
classNames: {
|
|
84
|
-
months: "flex flex-col sm:flex-row gap-2",
|
|
85
|
-
month: "flex flex-col gap-4",
|
|
86
|
-
dropdown_root: "relative",
|
|
87
|
-
nav: "absolute inset-x-0 top-0 flex h-8 items-center justify-between",
|
|
88
|
-
button_previous: cn(
|
|
89
|
-
buttonVariants({ variant: "outline" }),
|
|
90
|
-
"absolute left-1 top-1/2 h-7 w-7 -translate-y-1/2 bg-background p-0 opacity-70 hover:opacity-100"
|
|
91
|
-
),
|
|
92
|
-
button_next: cn(
|
|
93
|
-
buttonVariants({ variant: "outline" }),
|
|
94
|
-
"absolute right-1 top-1/2 h-7 w-7 -translate-y-1/2 bg-background p-0 opacity-70 hover:opacity-100"
|
|
95
|
-
),
|
|
96
|
-
month_grid: "w-full border-collapse",
|
|
97
|
-
weekdays: "flex",
|
|
98
|
-
weekday: "text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
|
|
99
|
-
week: "flex w-full mt-2",
|
|
100
|
-
day: cn(
|
|
101
|
-
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50",
|
|
102
|
-
props.mode === "range" ? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md" : "[&:has([aria-selected])]:rounded-md"
|
|
103
|
-
),
|
|
104
|
-
day_button: cn(
|
|
105
|
-
buttonVariants({ variant: "ghost" }),
|
|
106
|
-
"h-8 w-8 p-0 font-normal aria-selected:opacity-100"
|
|
107
|
-
),
|
|
108
|
-
range_start: "day-range-start aria-selected:bg-primary aria-selected:text-primary-foreground",
|
|
109
|
-
range_end: "day-range-end aria-selected:bg-primary aria-selected:text-primary-foreground",
|
|
110
|
-
selected: "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
|
111
|
-
today: "bg-accent text-accent-foreground",
|
|
112
|
-
outside: "day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
|
|
113
|
-
disabled: "text-muted-foreground opacity-50",
|
|
114
|
-
range_middle: "aria-selected:bg-accent aria-selected:text-accent-foreground",
|
|
115
|
-
hidden: "invisible",
|
|
116
|
-
...classNames
|
|
117
|
-
},
|
|
118
|
-
components: {
|
|
119
|
-
Chevron: ({ orientation }) => orientation === "left" ? /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
|
|
120
|
-
},
|
|
121
|
-
...props
|
|
122
|
-
}
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
Calendar.displayName = "Calendar";
|
|
126
94
|
var MONTHS = [
|
|
127
95
|
"Jan",
|
|
128
96
|
"Feb",
|
|
@@ -161,9 +129,9 @@ function ModernCalendar({
|
|
|
161
129
|
disabled = false
|
|
162
130
|
}) {
|
|
163
131
|
const today = /* @__PURE__ */ new Date();
|
|
164
|
-
const [viewDate, setViewDate] =
|
|
165
|
-
const [viewMode, setViewMode] =
|
|
166
|
-
const [yearRangeStart, setYearRangeStart] =
|
|
132
|
+
const [viewDate, setViewDate] = React5.useState(selected || today);
|
|
133
|
+
const [viewMode, setViewMode] = React5.useState("days");
|
|
134
|
+
const [yearRangeStart, setYearRangeStart] = React5.useState(
|
|
167
135
|
Math.floor((selected?.getFullYear() || today.getFullYear()) / 12) * 12
|
|
168
136
|
);
|
|
169
137
|
const getDaysInMonth = (year, month) => {
|
|
@@ -459,7 +427,7 @@ function DatePicker({
|
|
|
459
427
|
align = "start",
|
|
460
428
|
error = false
|
|
461
429
|
}) {
|
|
462
|
-
const [open, setOpen] =
|
|
430
|
+
const [open, setOpen] = React5.useState(false);
|
|
463
431
|
const handleSelect = (date) => {
|
|
464
432
|
onChange?.(date);
|
|
465
433
|
setOpen(false);
|
|
@@ -478,7 +446,7 @@ function DatePicker({
|
|
|
478
446
|
className
|
|
479
447
|
),
|
|
480
448
|
children: [
|
|
481
|
-
/* @__PURE__ */ jsx(Calendar
|
|
449
|
+
/* @__PURE__ */ jsx(Calendar, { className: "mr-2 h-4 w-4" }),
|
|
482
450
|
value ? format(value, dateFormat) : /* @__PURE__ */ jsx("span", { children: placeholder })
|
|
483
451
|
]
|
|
484
452
|
}
|
|
@@ -507,8 +475,8 @@ function DateRangePicker({
|
|
|
507
475
|
numberOfMonths = 2,
|
|
508
476
|
align = "start"
|
|
509
477
|
}) {
|
|
510
|
-
const [open, setOpen] =
|
|
511
|
-
const disabledMatcher =
|
|
478
|
+
const [open, setOpen] = React5.useState(false);
|
|
479
|
+
const disabledMatcher = React5.useMemo(() => {
|
|
512
480
|
const matchers = [];
|
|
513
481
|
if (fromDate) {
|
|
514
482
|
matchers.push({ before: fromDate });
|
|
@@ -531,7 +499,7 @@ function DateRangePicker({
|
|
|
531
499
|
className
|
|
532
500
|
),
|
|
533
501
|
children: [
|
|
534
|
-
/* @__PURE__ */ jsx(Calendar
|
|
502
|
+
/* @__PURE__ */ jsx(Calendar, { className: "mr-2 h-4 w-4" }),
|
|
535
503
|
value?.from ? value.to ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
536
504
|
format(value.from, dateFormat),
|
|
537
505
|
" -",
|
|
@@ -542,9 +510,10 @@ function DateRangePicker({
|
|
|
542
510
|
}
|
|
543
511
|
) }),
|
|
544
512
|
/* @__PURE__ */ jsx(PopoverContent, { className: "w-auto p-0", align, children: /* @__PURE__ */ jsx(
|
|
545
|
-
Calendar,
|
|
513
|
+
Calendar$1,
|
|
546
514
|
{
|
|
547
515
|
mode: "range",
|
|
516
|
+
captionLayout: "dropdown",
|
|
548
517
|
selected: value,
|
|
549
518
|
onSelect: onChange,
|
|
550
519
|
disabled: disabledMatcher,
|
|
@@ -749,597 +718,9 @@ function ComparisonSelector({
|
|
|
749
718
|
)
|
|
750
719
|
] });
|
|
751
720
|
}
|
|
752
|
-
|
|
753
|
-
// src/blocks/data-table/data-table-styles.ts
|
|
754
|
-
var dataTableTopperButtonProps = {
|
|
755
|
-
variant: "ghost-icon",
|
|
756
|
-
size: "icon-sm"
|
|
757
|
-
};
|
|
758
|
-
var dataTableTopperResponsiveClasses = "w-8 @min-[450px]:w-auto @min-[450px]:px-2";
|
|
759
|
-
var dataTableTopperOpenStateClasses = "data-[state=open]:text-foreground";
|
|
760
|
-
var dataTableTopperIconClasses = "text-icon hover:text-icon-hover [&_svg]:transition-transform [&_svg]:duration-200 hover:[&_svg]:scale-110";
|
|
761
|
-
function DataTableAddButton({
|
|
762
|
-
label = "Add",
|
|
763
|
-
icon,
|
|
764
|
-
responsiveLabel = true,
|
|
765
|
-
className,
|
|
766
|
-
children,
|
|
767
|
-
...props
|
|
768
|
-
}) {
|
|
769
|
-
const context = useDataTableContext();
|
|
770
|
-
const fontSizeClass = context?.fontSizeClass ?? "text-xs";
|
|
771
|
-
const iconElement = icon ?? /* @__PURE__ */ jsx(Plus, { className: "size-4" });
|
|
772
|
-
return /* @__PURE__ */ jsxs(
|
|
773
|
-
Button,
|
|
774
|
-
{
|
|
775
|
-
...dataTableTopperButtonProps,
|
|
776
|
-
className: cn(
|
|
777
|
-
fontSizeClass,
|
|
778
|
-
responsiveLabel ? dataTableTopperResponsiveClasses : "px-2 w-auto",
|
|
779
|
-
className
|
|
780
|
-
),
|
|
781
|
-
...props,
|
|
782
|
-
children: [
|
|
783
|
-
iconElement,
|
|
784
|
-
responsiveLabel ? /* @__PURE__ */ jsx("span", { className: "hidden @min-[450px]:inline", children: children ?? label }) : /* @__PURE__ */ jsx("span", { children: children ?? label })
|
|
785
|
-
]
|
|
786
|
-
}
|
|
787
|
-
);
|
|
788
|
-
}
|
|
789
|
-
function DataTableColumnMenuSub({
|
|
790
|
-
label,
|
|
791
|
-
icon,
|
|
792
|
-
children
|
|
793
|
-
}) {
|
|
794
|
-
return /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
|
|
795
|
-
/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { className: "flex items-center gap-2", children: [
|
|
796
|
-
icon ?? /* @__PURE__ */ jsx(ListOrdered, { className: "size-4 text-muted-foreground" }),
|
|
797
|
-
label
|
|
798
|
-
] }),
|
|
799
|
-
/* @__PURE__ */ jsx(DropdownMenuSubContent, { alignOffset: -5, sideOffset: 5, children })
|
|
800
|
-
] });
|
|
801
|
-
}
|
|
802
|
-
function escapeCsvField(value) {
|
|
803
|
-
if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
|
|
804
|
-
return `"${value.replace(/"/g, '""')}"`;
|
|
805
|
-
}
|
|
806
|
-
return value;
|
|
807
|
-
}
|
|
808
|
-
function formatCsvValue(value) {
|
|
809
|
-
if (value === null || value === void 0) {
|
|
810
|
-
return "";
|
|
811
|
-
}
|
|
812
|
-
if (typeof value === "boolean") {
|
|
813
|
-
return value ? "Yes" : "No";
|
|
814
|
-
}
|
|
815
|
-
if (value instanceof Date) {
|
|
816
|
-
return value.toISOString();
|
|
817
|
-
}
|
|
818
|
-
if (typeof value === "object") {
|
|
819
|
-
try {
|
|
820
|
-
return JSON.stringify(value);
|
|
821
|
-
} catch {
|
|
822
|
-
return String(value);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
return String(value);
|
|
826
|
-
}
|
|
827
|
-
function serializeTableExport({
|
|
828
|
-
table,
|
|
829
|
-
visibleColumnsOnly = true,
|
|
830
|
-
selectedRowsOnly = false,
|
|
831
|
-
customHeaders = {},
|
|
832
|
-
excludeColumns = [],
|
|
833
|
-
formatters = {}
|
|
834
|
-
}) {
|
|
835
|
-
const allColumns = visibleColumnsOnly ? table.getVisibleLeafColumns() : table.getAllLeafColumns();
|
|
836
|
-
const columns = allColumns.filter((col) => {
|
|
837
|
-
const colId = col.id;
|
|
838
|
-
if (["select", "selection", "actions", "_actions"].includes(colId)) {
|
|
839
|
-
return false;
|
|
840
|
-
}
|
|
841
|
-
return !excludeColumns.includes(colId);
|
|
842
|
-
});
|
|
843
|
-
const tableRows = selectedRowsOnly ? table.getFilteredSelectedRowModel().rows : table.getFilteredRowModel().rows;
|
|
844
|
-
return {
|
|
845
|
-
headers: columns.map((col) => customHeaders[col.id] ?? col.id),
|
|
846
|
-
rows: tableRows.map(
|
|
847
|
-
(row) => columns.map((col) => {
|
|
848
|
-
const cellValue = row.getValue(col.id);
|
|
849
|
-
const formatter = formatters[col.id];
|
|
850
|
-
return formatter ? formatter(cellValue) : formatCsvValue(cellValue);
|
|
851
|
-
})
|
|
852
|
-
)
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
function exportToCsv({
|
|
856
|
-
table,
|
|
857
|
-
filename = "export",
|
|
858
|
-
visibleColumnsOnly = true,
|
|
859
|
-
selectedRowsOnly = false,
|
|
860
|
-
customHeaders = {},
|
|
861
|
-
excludeColumns = [],
|
|
862
|
-
formatters = {}
|
|
863
|
-
}) {
|
|
864
|
-
const { headers, rows } = serializeTableExport({
|
|
865
|
-
table,
|
|
866
|
-
visibleColumnsOnly,
|
|
867
|
-
selectedRowsOnly,
|
|
868
|
-
customHeaders,
|
|
869
|
-
excludeColumns,
|
|
870
|
-
formatters
|
|
871
|
-
});
|
|
872
|
-
const csvContent = [
|
|
873
|
-
headers.map(escapeCsvField).join(","),
|
|
874
|
-
...rows.map((row) => row.map(escapeCsvField).join(","))
|
|
875
|
-
].join("\n");
|
|
876
|
-
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
|
|
877
|
-
const url = URL.createObjectURL(blob);
|
|
878
|
-
const link = document.createElement("a");
|
|
879
|
-
link.setAttribute("href", url);
|
|
880
|
-
link.setAttribute("download", `${filename}.csv`);
|
|
881
|
-
link.style.visibility = "hidden";
|
|
882
|
-
document.body.appendChild(link);
|
|
883
|
-
link.click();
|
|
884
|
-
document.body.removeChild(link);
|
|
885
|
-
URL.revokeObjectURL(url);
|
|
886
|
-
}
|
|
887
|
-
function exportToExcel({
|
|
888
|
-
table,
|
|
889
|
-
filename = "export",
|
|
890
|
-
visibleColumnsOnly = true,
|
|
891
|
-
selectedRowsOnly = false,
|
|
892
|
-
customHeaders = {},
|
|
893
|
-
excludeColumns = [],
|
|
894
|
-
formatters = {}
|
|
895
|
-
}) {
|
|
896
|
-
const { headers, rows } = serializeTableExport({
|
|
897
|
-
table,
|
|
898
|
-
visibleColumnsOnly,
|
|
899
|
-
selectedRowsOnly,
|
|
900
|
-
customHeaders,
|
|
901
|
-
excludeColumns,
|
|
902
|
-
formatters
|
|
903
|
-
});
|
|
904
|
-
const sheetRows = [
|
|
905
|
-
headers.map((header) => ({ value: header, style: "header" })),
|
|
906
|
-
...rows.map(
|
|
907
|
-
(row) => row.map((cell) => {
|
|
908
|
-
const trimmed = cell.trim();
|
|
909
|
-
const isNumericPattern = trimmed !== "" && /^-?\d+(\.\d+)?$/.test(trimmed);
|
|
910
|
-
const hasLeadingZero = /^0\d+$/.test(trimmed) || /^-0\d+$/.test(trimmed);
|
|
911
|
-
const numValue = Number(trimmed);
|
|
912
|
-
const isNumber = isNumericPattern && !hasLeadingZero && !Number.isNaN(numValue);
|
|
913
|
-
if (isNumber) {
|
|
914
|
-
return {
|
|
915
|
-
value: numValue,
|
|
916
|
-
type: "Number",
|
|
917
|
-
style: "number"
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
|
-
return { value: cell, style: "text" };
|
|
921
|
-
})
|
|
922
|
-
)
|
|
923
|
-
];
|
|
924
|
-
const xmlContent = buildSpreadsheetWorkbookXml({
|
|
925
|
-
worksheetName: "Data",
|
|
926
|
-
rows: sheetRows
|
|
927
|
-
});
|
|
928
|
-
downloadExcelXml(xmlContent, filename);
|
|
929
|
-
}
|
|
930
|
-
function DataTableExportButton({
|
|
931
|
-
table,
|
|
932
|
-
onExportCsv,
|
|
933
|
-
onExportExcel,
|
|
934
|
-
onExport,
|
|
935
|
-
// deprecated, maps to CSV
|
|
936
|
-
filename = "export",
|
|
937
|
-
label = "Export",
|
|
938
|
-
disabled = false,
|
|
939
|
-
selectedRowsOnly = false,
|
|
940
|
-
excludeColumns = [],
|
|
941
|
-
customHeaders = {},
|
|
942
|
-
formatters = {}
|
|
943
|
-
}) {
|
|
944
|
-
const context = useDataTableContext();
|
|
945
|
-
const fontSizeClass = context?.fontSizeClass ?? "text-xs";
|
|
946
|
-
const [isExporting, setIsExporting] = React12.useState(false);
|
|
947
|
-
const [exportingFormat, setExportingFormat] = React12.useState(null);
|
|
948
|
-
const handleExport = React12.useCallback(
|
|
949
|
-
async (format3) => {
|
|
950
|
-
if (disabled) return;
|
|
951
|
-
setIsExporting(true);
|
|
952
|
-
setExportingFormat(format3);
|
|
953
|
-
try {
|
|
954
|
-
if (table) {
|
|
955
|
-
if (format3 === "csv") {
|
|
956
|
-
exportToCsv({
|
|
957
|
-
table,
|
|
958
|
-
filename,
|
|
959
|
-
selectedRowsOnly,
|
|
960
|
-
excludeColumns,
|
|
961
|
-
customHeaders,
|
|
962
|
-
formatters
|
|
963
|
-
});
|
|
964
|
-
} else {
|
|
965
|
-
exportToExcel({
|
|
966
|
-
table,
|
|
967
|
-
filename,
|
|
968
|
-
selectedRowsOnly,
|
|
969
|
-
excludeColumns,
|
|
970
|
-
customHeaders,
|
|
971
|
-
formatters
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
} else {
|
|
975
|
-
if (format3 === "csv") {
|
|
976
|
-
await (onExportCsv ?? onExport)?.();
|
|
977
|
-
} else {
|
|
978
|
-
await onExportExcel?.();
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
} finally {
|
|
982
|
-
setIsExporting(false);
|
|
983
|
-
setExportingFormat(null);
|
|
984
|
-
}
|
|
985
|
-
},
|
|
986
|
-
[
|
|
987
|
-
table,
|
|
988
|
-
onExportCsv,
|
|
989
|
-
onExportExcel,
|
|
990
|
-
onExport,
|
|
991
|
-
filename,
|
|
992
|
-
selectedRowsOnly,
|
|
993
|
-
excludeColumns,
|
|
994
|
-
customHeaders,
|
|
995
|
-
formatters,
|
|
996
|
-
disabled
|
|
997
|
-
]
|
|
998
|
-
);
|
|
999
|
-
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
1000
|
-
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
1001
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
1002
|
-
Button,
|
|
1003
|
-
{
|
|
1004
|
-
...dataTableTopperButtonProps,
|
|
1005
|
-
disabled: isExporting || disabled,
|
|
1006
|
-
"aria-label": label,
|
|
1007
|
-
className: dataTableTopperOpenStateClasses,
|
|
1008
|
-
children: isExporting ? /* @__PURE__ */ jsx(Spinner, { className: "size-4" }) : /* @__PURE__ */ jsx(Download, { className: "size-4" })
|
|
1009
|
-
}
|
|
1010
|
-
) }) }),
|
|
1011
|
-
/* @__PURE__ */ jsx(TooltipContent, { className: fontSizeClass, children: label })
|
|
1012
|
-
] }),
|
|
1013
|
-
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-44", children: [
|
|
1014
|
-
/* @__PURE__ */ jsx(
|
|
1015
|
-
DropdownMenuLabel,
|
|
1016
|
-
{
|
|
1017
|
-
className: cn("font-normal text-muted-foreground", fontSizeClass),
|
|
1018
|
-
children: "Export Data"
|
|
1019
|
-
}
|
|
1020
|
-
),
|
|
1021
|
-
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
1022
|
-
/* @__PURE__ */ jsxs(
|
|
1023
|
-
DropdownMenuItem,
|
|
1024
|
-
{
|
|
1025
|
-
onClick: () => handleExport("csv"),
|
|
1026
|
-
disabled: isExporting,
|
|
1027
|
-
className: cn("gap-2", fontSizeClass),
|
|
1028
|
-
children: [
|
|
1029
|
-
/* @__PURE__ */ jsx(FileText, { className: dataTableTopperIconClasses }),
|
|
1030
|
-
/* @__PURE__ */ jsx("span", { children: "CSV" }),
|
|
1031
|
-
exportingFormat === "csv" && /* @__PURE__ */ jsx(Spinner, { className: "size-3 ml-auto" })
|
|
1032
|
-
]
|
|
1033
|
-
}
|
|
1034
|
-
),
|
|
1035
|
-
/* @__PURE__ */ jsxs(
|
|
1036
|
-
DropdownMenuItem,
|
|
1037
|
-
{
|
|
1038
|
-
onClick: () => handleExport("excel"),
|
|
1039
|
-
disabled: isExporting,
|
|
1040
|
-
className: cn("gap-2", fontSizeClass),
|
|
1041
|
-
children: [
|
|
1042
|
-
/* @__PURE__ */ jsx(FileSpreadsheet, { className: dataTableTopperIconClasses }),
|
|
1043
|
-
/* @__PURE__ */ jsx("span", { children: "Excel" }),
|
|
1044
|
-
exportingFormat === "excel" && /* @__PURE__ */ jsx(Spinner, { className: "size-3 ml-auto" })
|
|
1045
|
-
]
|
|
1046
|
-
}
|
|
1047
|
-
)
|
|
1048
|
-
] })
|
|
1049
|
-
] });
|
|
1050
|
-
}
|
|
1051
|
-
function DataTablePagination({
|
|
1052
|
-
page,
|
|
1053
|
-
pageSize,
|
|
1054
|
-
pageCount,
|
|
1055
|
-
totalCount,
|
|
1056
|
-
selectedCount = 0,
|
|
1057
|
-
pageSizeOptions = [10, 20, 30, 40, 50],
|
|
1058
|
-
onPageChange,
|
|
1059
|
-
onPageSizeChange,
|
|
1060
|
-
className,
|
|
1061
|
-
...props
|
|
1062
|
-
}) {
|
|
1063
|
-
const displayPageCount = Math.max(1, pageCount);
|
|
1064
|
-
const canGoPrevious = page > 1;
|
|
1065
|
-
const canGoNext = page < displayPageCount;
|
|
1066
|
-
return /* @__PURE__ */ jsxs(
|
|
1067
|
-
"div",
|
|
1068
|
-
{
|
|
1069
|
-
className: cn(
|
|
1070
|
-
"flex w-full flex-row items-center justify-between gap-3 overflow-auto p-1 sm:gap-8",
|
|
1071
|
-
className
|
|
1072
|
-
),
|
|
1073
|
-
...props,
|
|
1074
|
-
children: [
|
|
1075
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
1076
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1 sm:gap-2 lg:gap-6", children: [
|
|
1077
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
|
|
1078
|
-
/* @__PURE__ */ jsxs("p", { className: "whitespace-nowrap text-[length:var(--text-xs)] font-light text-muted-foreground", children: [
|
|
1079
|
-
/* @__PURE__ */ jsx("span", { className: "hidden lg:inline", children: "Rows per page" }),
|
|
1080
|
-
/* @__PURE__ */ jsx("span", { className: "lg:hidden", children: "Rows" })
|
|
1081
|
-
] }),
|
|
1082
|
-
/* @__PURE__ */ jsxs(
|
|
1083
|
-
Select,
|
|
1084
|
-
{
|
|
1085
|
-
value: `${pageSize}`,
|
|
1086
|
-
onValueChange: (value) => onPageSizeChange(Number(value)),
|
|
1087
|
-
children: [
|
|
1088
|
-
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-6 w-[60px] px-2 text-[length:var(--text-xs)] focus:ring-0 focus:ring-offset-0 hover:bg-accent transition-colors", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: pageSize }) }),
|
|
1089
|
-
/* @__PURE__ */ jsx(SelectContent, { side: "top", children: pageSizeOptions.map((size) => /* @__PURE__ */ jsx(
|
|
1090
|
-
SelectItem,
|
|
1091
|
-
{
|
|
1092
|
-
value: `${size}`,
|
|
1093
|
-
className: "text-[length:var(--text-xs)] h-7",
|
|
1094
|
-
children: size
|
|
1095
|
-
},
|
|
1096
|
-
size
|
|
1097
|
-
)) })
|
|
1098
|
-
]
|
|
1099
|
-
}
|
|
1100
|
-
)
|
|
1101
|
-
] }),
|
|
1102
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-1", children: [
|
|
1103
|
-
/* @__PURE__ */ jsx(
|
|
1104
|
-
Button,
|
|
1105
|
-
{
|
|
1106
|
-
"aria-label": "Go to first page",
|
|
1107
|
-
variant: "ghost",
|
|
1108
|
-
className: "hidden size-7 p-0 lg:flex hover:bg-accent",
|
|
1109
|
-
onClick: () => onPageChange(1),
|
|
1110
|
-
disabled: !canGoPrevious,
|
|
1111
|
-
children: /* @__PURE__ */ jsx(ChevronsLeft, { className: "size-3.5" })
|
|
1112
|
-
}
|
|
1113
|
-
),
|
|
1114
|
-
/* @__PURE__ */ jsx(
|
|
1115
|
-
Button,
|
|
1116
|
-
{
|
|
1117
|
-
"aria-label": "Go to previous page",
|
|
1118
|
-
variant: "ghost",
|
|
1119
|
-
className: "size-7 p-0 hover:bg-accent",
|
|
1120
|
-
onClick: () => onPageChange(page - 1),
|
|
1121
|
-
disabled: !canGoPrevious,
|
|
1122
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-3.5" })
|
|
1123
|
-
}
|
|
1124
|
-
),
|
|
1125
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center text-[length:var(--text-xs)] font-light text-muted-foreground whitespace-nowrap px-1", children: [
|
|
1126
|
-
/* @__PURE__ */ jsxs("span", { className: "hidden lg:inline", children: [
|
|
1127
|
-
"Page ",
|
|
1128
|
-
page,
|
|
1129
|
-
" of ",
|
|
1130
|
-
displayPageCount
|
|
1131
|
-
] }),
|
|
1132
|
-
/* @__PURE__ */ jsxs("span", { className: "lg:hidden", children: [
|
|
1133
|
-
page,
|
|
1134
|
-
" / ",
|
|
1135
|
-
displayPageCount
|
|
1136
|
-
] })
|
|
1137
|
-
] }),
|
|
1138
|
-
/* @__PURE__ */ jsx(
|
|
1139
|
-
Button,
|
|
1140
|
-
{
|
|
1141
|
-
"aria-label": "Go to next page",
|
|
1142
|
-
variant: "ghost",
|
|
1143
|
-
className: "size-7 p-0 hover:bg-accent",
|
|
1144
|
-
onClick: () => onPageChange(page + 1),
|
|
1145
|
-
disabled: !canGoNext,
|
|
1146
|
-
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5" })
|
|
1147
|
-
}
|
|
1148
|
-
),
|
|
1149
|
-
/* @__PURE__ */ jsx(
|
|
1150
|
-
Button,
|
|
1151
|
-
{
|
|
1152
|
-
"aria-label": "Go to last page",
|
|
1153
|
-
variant: "ghost",
|
|
1154
|
-
className: "hidden size-7 p-0 lg:flex hover:bg-accent",
|
|
1155
|
-
onClick: () => onPageChange(displayPageCount),
|
|
1156
|
-
disabled: !canGoNext,
|
|
1157
|
-
children: /* @__PURE__ */ jsx(ChevronsRight, { className: "size-3.5" })
|
|
1158
|
-
}
|
|
1159
|
-
)
|
|
1160
|
-
] })
|
|
1161
|
-
] })
|
|
1162
|
-
]
|
|
1163
|
-
}
|
|
1164
|
-
);
|
|
1165
|
-
}
|
|
1166
|
-
var iconButtonVariants = cva(
|
|
1167
|
-
"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",
|
|
1168
|
-
{
|
|
1169
|
-
variants: {
|
|
1170
|
-
variant: {
|
|
1171
|
-
default: "text-muted-foreground hover:text-foreground hover:bg-accent",
|
|
1172
|
-
ghost: "text-muted-foreground/50 hover:text-foreground hover:bg-transparent",
|
|
1173
|
-
delete: "text-muted-foreground/50 hover:text-destructive hover:bg-transparent",
|
|
1174
|
-
edit: "text-muted-foreground/50 hover:text-foreground hover:bg-transparent",
|
|
1175
|
-
destructive: "text-muted-foreground/50 hover:text-destructive hover:bg-transparent",
|
|
1176
|
-
success: "text-muted-foreground/50 hover:text-green-600 hover:bg-transparent",
|
|
1177
|
-
successActive: "text-green-600 hover:text-muted-foreground/60 hover:bg-transparent"
|
|
1178
|
-
},
|
|
1179
|
-
size: {
|
|
1180
|
-
default: "h-8 w-8 [&_svg]:size-4",
|
|
1181
|
-
sm: "h-6 w-6 [&_svg]:size-3.5",
|
|
1182
|
-
xs: "h-5 w-5 [&_svg]:size-3",
|
|
1183
|
-
lg: "h-10 w-10 [&_svg]:size-5"
|
|
1184
|
-
}
|
|
1185
|
-
},
|
|
1186
|
-
defaultVariants: {
|
|
1187
|
-
variant: "default",
|
|
1188
|
-
size: "default"
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
);
|
|
1192
|
-
function IconButton({ className, variant, size, ...props }) {
|
|
1193
|
-
return /* @__PURE__ */ jsx(
|
|
1194
|
-
"button",
|
|
1195
|
-
{
|
|
1196
|
-
type: "button",
|
|
1197
|
-
"data-slot": "icon-button",
|
|
1198
|
-
className: cn(iconButtonVariants({ variant, size, className })),
|
|
1199
|
-
...props
|
|
1200
|
-
}
|
|
1201
|
-
);
|
|
1202
|
-
}
|
|
1203
|
-
function useIsDesktop() {
|
|
1204
|
-
const [isDesktop, setIsDesktop] = React12.useState(false);
|
|
1205
|
-
React12.useEffect(() => {
|
|
1206
|
-
const mediaQuery = window.matchMedia("(min-width: 768px)");
|
|
1207
|
-
setIsDesktop(mediaQuery.matches);
|
|
1208
|
-
const handler = (e) => setIsDesktop(e.matches);
|
|
1209
|
-
mediaQuery.addEventListener("change", handler);
|
|
1210
|
-
return () => mediaQuery.removeEventListener("change", handler);
|
|
1211
|
-
}, []);
|
|
1212
|
-
return isDesktop;
|
|
1213
|
-
}
|
|
1214
|
-
function ActionsDropdown({
|
|
1215
|
-
actions,
|
|
1216
|
-
fontSizeClass,
|
|
1217
|
-
density
|
|
1218
|
-
}) {
|
|
1219
|
-
const isCompact = density === "compact";
|
|
1220
|
-
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
1221
|
-
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1222
|
-
IconButton,
|
|
1223
|
-
{
|
|
1224
|
-
variant: "ghost",
|
|
1225
|
-
size: isCompact ? "xs" : "sm",
|
|
1226
|
-
className: "data-[state=open]:bg-muted",
|
|
1227
|
-
children: [
|
|
1228
|
-
/* @__PURE__ */ jsx(MoreHorizontal, { className: isCompact ? "size-3.5" : "size-4" }),
|
|
1229
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Open menu" })
|
|
1230
|
-
]
|
|
1231
|
-
}
|
|
1232
|
-
) }),
|
|
1233
|
-
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", className: "w-40", children: actions.map((action, index) => /* @__PURE__ */ jsxs("div", { children: [
|
|
1234
|
-
action.separatorBefore && index > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
1235
|
-
/* @__PURE__ */ jsxs(
|
|
1236
|
-
DropdownMenuItem,
|
|
1237
|
-
{
|
|
1238
|
-
onClick: action.onClick,
|
|
1239
|
-
disabled: action.disabled,
|
|
1240
|
-
className: cn(
|
|
1241
|
-
fontSizeClass,
|
|
1242
|
-
action.destructive && "hover:text-destructive hover:bg-destructive/10",
|
|
1243
|
-
action.success && "hover:text-success hover:bg-success/10",
|
|
1244
|
-
action.successActive && "text-green-600 hover:text-muted-foreground hover:bg-accent"
|
|
1245
|
-
),
|
|
1246
|
-
children: [
|
|
1247
|
-
action.icon && /* @__PURE__ */ jsx(
|
|
1248
|
-
"span",
|
|
1249
|
-
{
|
|
1250
|
-
className: cn(
|
|
1251
|
-
"mr-2",
|
|
1252
|
-
action.destructive && "group-hover:text-destructive",
|
|
1253
|
-
action.success && "group-hover:text-success",
|
|
1254
|
-
action.successActive && "text-green-600 group-hover:text-muted-foreground"
|
|
1255
|
-
),
|
|
1256
|
-
children: action.icon
|
|
1257
|
-
}
|
|
1258
|
-
),
|
|
1259
|
-
action.label
|
|
1260
|
-
]
|
|
1261
|
-
}
|
|
1262
|
-
)
|
|
1263
|
-
] }, action.label)) })
|
|
1264
|
-
] });
|
|
1265
|
-
}
|
|
1266
|
-
function ActionsInline({
|
|
1267
|
-
actions,
|
|
1268
|
-
fontSizeClass,
|
|
1269
|
-
density
|
|
1270
|
-
}) {
|
|
1271
|
-
const isCompact = density === "compact";
|
|
1272
|
-
return /* @__PURE__ */ jsx("div", { className: cn("flex items-center", isCompact ? "gap-0.5" : "gap-1"), children: actions.map((action) => {
|
|
1273
|
-
const variant = action.destructive ? "delete" : action.successActive ? "successActive" : action.success ? "success" : "ghost";
|
|
1274
|
-
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
1275
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1276
|
-
IconButton,
|
|
1277
|
-
{
|
|
1278
|
-
variant,
|
|
1279
|
-
size: isCompact ? "xs" : "default",
|
|
1280
|
-
onClick: action.onClick,
|
|
1281
|
-
disabled: action.disabled,
|
|
1282
|
-
children: [
|
|
1283
|
-
action.icon,
|
|
1284
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: action.label })
|
|
1285
|
-
]
|
|
1286
|
-
}
|
|
1287
|
-
) }),
|
|
1288
|
-
/* @__PURE__ */ jsx(TooltipContent, { className: fontSizeClass, children: action.label })
|
|
1289
|
-
] }, action.label);
|
|
1290
|
-
}) });
|
|
1291
|
-
}
|
|
1292
|
-
function DataTableRowActions({
|
|
1293
|
-
actions,
|
|
1294
|
-
mode = "dropdown"
|
|
1295
|
-
}) {
|
|
1296
|
-
const context = useDataTableContext();
|
|
1297
|
-
const fontSizeClass = context?.fontSizeClass ?? "text-xs";
|
|
1298
|
-
const density = context?.density ?? "comfy";
|
|
1299
|
-
const isDesktop = useIsDesktop();
|
|
1300
|
-
if (actions.length === 0) return null;
|
|
1301
|
-
if (mode === "dropdown") {
|
|
1302
|
-
return /* @__PURE__ */ jsx(
|
|
1303
|
-
ActionsDropdown,
|
|
1304
|
-
{
|
|
1305
|
-
actions,
|
|
1306
|
-
fontSizeClass,
|
|
1307
|
-
density
|
|
1308
|
-
}
|
|
1309
|
-
);
|
|
1310
|
-
}
|
|
1311
|
-
if (mode === "inline") {
|
|
1312
|
-
return /* @__PURE__ */ jsx(
|
|
1313
|
-
ActionsInline,
|
|
1314
|
-
{
|
|
1315
|
-
actions,
|
|
1316
|
-
fontSizeClass,
|
|
1317
|
-
density
|
|
1318
|
-
}
|
|
1319
|
-
);
|
|
1320
|
-
}
|
|
1321
|
-
if (isDesktop) {
|
|
1322
|
-
return /* @__PURE__ */ jsx(
|
|
1323
|
-
ActionsInline,
|
|
1324
|
-
{
|
|
1325
|
-
actions,
|
|
1326
|
-
fontSizeClass,
|
|
1327
|
-
density
|
|
1328
|
-
}
|
|
1329
|
-
);
|
|
1330
|
-
}
|
|
1331
|
-
return /* @__PURE__ */ jsx(
|
|
1332
|
-
ActionsDropdown,
|
|
1333
|
-
{
|
|
1334
|
-
actions,
|
|
1335
|
-
fontSizeClass,
|
|
1336
|
-
density
|
|
1337
|
-
}
|
|
1338
|
-
);
|
|
1339
|
-
}
|
|
1340
721
|
var STORAGE_PREFIX = "dt-settings-";
|
|
1341
722
|
function useDataTableSettings(tableId, settings) {
|
|
1342
|
-
const [values, setValues] =
|
|
723
|
+
const [values, setValues] = React5.useState(() => {
|
|
1343
724
|
const defaults = {};
|
|
1344
725
|
for (const s of settings) {
|
|
1345
726
|
defaults[s.id] = s.defaultValue;
|
|
@@ -1356,7 +737,7 @@ function useDataTableSettings(tableId, settings) {
|
|
|
1356
737
|
}
|
|
1357
738
|
return defaults;
|
|
1358
739
|
});
|
|
1359
|
-
const onChange =
|
|
740
|
+
const onChange = React5.useCallback(
|
|
1360
741
|
(id, value) => {
|
|
1361
742
|
setValues((prev) => {
|
|
1362
743
|
const next = { ...prev, [id]: value };
|
|
@@ -1374,7 +755,7 @@ function useDataTableSettings(tableId, settings) {
|
|
|
1374
755
|
},
|
|
1375
756
|
[tableId]
|
|
1376
757
|
);
|
|
1377
|
-
const getSetting =
|
|
758
|
+
const getSetting = React5.useCallback(
|
|
1378
759
|
(id) => values[id],
|
|
1379
760
|
[values]
|
|
1380
761
|
);
|
|
@@ -1440,1149 +821,25 @@ function DataTableSettings({
|
|
|
1440
821
|
] }) })
|
|
1441
822
|
] }) });
|
|
1442
823
|
}
|
|
1443
|
-
function
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
filterCount = 0,
|
|
1457
|
-
cellWidths = ["auto"],
|
|
1458
|
-
withViewOptions = true,
|
|
1459
|
-
withPagination = true,
|
|
1460
|
-
shrinkZero = false,
|
|
824
|
+
function Combobox({
|
|
825
|
+
options,
|
|
826
|
+
value,
|
|
827
|
+
onValueChange,
|
|
828
|
+
placeholder = "Select...",
|
|
829
|
+
mutedPlaceholder = true,
|
|
830
|
+
searchPlaceholder = "Search...",
|
|
831
|
+
emptyText = "No results found.",
|
|
832
|
+
disabled = false,
|
|
833
|
+
allowCreate = false,
|
|
834
|
+
createLabel = "Create new",
|
|
835
|
+
onCreateNew,
|
|
836
|
+
loading = false,
|
|
1461
837
|
className,
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
);
|
|
1468
|
-
return /* @__PURE__ */ jsxs(
|
|
1469
|
-
"div",
|
|
1470
|
-
{
|
|
1471
|
-
className: cn("flex w-full flex-col gap-2.5 overflow-auto", className),
|
|
1472
|
-
...props,
|
|
1473
|
-
children: [
|
|
1474
|
-
/* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between gap-2 overflow-auto p-1", children: [
|
|
1475
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-2", children: [
|
|
1476
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-[150px] lg:w-[250px]" }),
|
|
1477
|
-
filterCount > 0 && Array.from({ length: filterCount }).map((_, i) => /* @__PURE__ */ jsx(
|
|
1478
|
-
Skeleton,
|
|
1479
|
-
{
|
|
1480
|
-
className: "h-8 w-20 border-dashed"
|
|
1481
|
-
},
|
|
1482
|
-
`filter-${i}`
|
|
1483
|
-
))
|
|
1484
|
-
] }),
|
|
1485
|
-
withViewOptions && /* @__PURE__ */ jsx(Skeleton, { className: "hidden h-8 w-20 lg:block" })
|
|
1486
|
-
] }),
|
|
1487
|
-
/* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
1488
|
-
/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { className: "hover:bg-transparent", children: widths.map((width, index) => /* @__PURE__ */ jsx(
|
|
1489
|
-
TableHead,
|
|
1490
|
-
{
|
|
1491
|
-
style: {
|
|
1492
|
-
width: shrinkZero && width === "auto" ? 0 : width,
|
|
1493
|
-
minWidth: shrinkZero ? 0 : void 0
|
|
1494
|
-
},
|
|
1495
|
-
children: /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-full" })
|
|
1496
|
-
},
|
|
1497
|
-
`header-${index}`
|
|
1498
|
-
)) }) }),
|
|
1499
|
-
/* @__PURE__ */ jsx(TableBody, { children: Array.from({ length: rowCount }).map((_, rowIndex) => /* @__PURE__ */ jsx(
|
|
1500
|
-
TableRow,
|
|
1501
|
-
{
|
|
1502
|
-
className: "hover:bg-transparent",
|
|
1503
|
-
children: widths.map((width, cellIndex) => /* @__PURE__ */ jsx(
|
|
1504
|
-
TableCell,
|
|
1505
|
-
{
|
|
1506
|
-
style: {
|
|
1507
|
-
width: shrinkZero && width === "auto" ? 0 : width,
|
|
1508
|
-
minWidth: shrinkZero ? 0 : void 0
|
|
1509
|
-
},
|
|
1510
|
-
children: /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-full" })
|
|
1511
|
-
},
|
|
1512
|
-
`cell-${rowIndex}-${cellIndex}`
|
|
1513
|
-
))
|
|
1514
|
-
},
|
|
1515
|
-
`row-${rowIndex}`
|
|
1516
|
-
)) })
|
|
1517
|
-
] }) }),
|
|
1518
|
-
withPagination && /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between gap-4 overflow-auto p-1 sm:gap-8", children: [
|
|
1519
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-40 shrink-0" }),
|
|
1520
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 sm:gap-6 lg:gap-8", children: [
|
|
1521
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1522
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-24" }),
|
|
1523
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-[70px]" })
|
|
1524
|
-
] }),
|
|
1525
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" }),
|
|
1526
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1527
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "hidden size-8 lg:block" }),
|
|
1528
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "size-8" }),
|
|
1529
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "size-8" }),
|
|
1530
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "hidden size-8 lg:block" })
|
|
1531
|
-
] })
|
|
1532
|
-
] })
|
|
1533
|
-
] })
|
|
1534
|
-
]
|
|
1535
|
-
}
|
|
1536
|
-
);
|
|
1537
|
-
}
|
|
1538
|
-
var summaryOptions = {
|
|
1539
|
-
text: [
|
|
1540
|
-
{ value: "none", label: "None" },
|
|
1541
|
-
{ value: "count", label: "Count" },
|
|
1542
|
-
{ value: "count_unique", label: "Count unique" },
|
|
1543
|
-
{ value: "percent_empty", label: "% Empty" },
|
|
1544
|
-
{ value: "percent_filled", label: "% Filled" }
|
|
1545
|
-
],
|
|
1546
|
-
number: [
|
|
1547
|
-
{ value: "none", label: "None" },
|
|
1548
|
-
{ value: "count", label: "Count" },
|
|
1549
|
-
{ value: "sum", label: "Sum" },
|
|
1550
|
-
{ value: "average", label: "Average" },
|
|
1551
|
-
{ value: "median", label: "Median" },
|
|
1552
|
-
{ value: "min", label: "Min" },
|
|
1553
|
-
{ value: "max", label: "Max" },
|
|
1554
|
-
{ value: "range", label: "Range" },
|
|
1555
|
-
{ value: "percent_empty", label: "% Empty" },
|
|
1556
|
-
{ value: "percent_filled", label: "% Filled" }
|
|
1557
|
-
],
|
|
1558
|
-
boolean: [
|
|
1559
|
-
{ value: "none", label: "None" },
|
|
1560
|
-
{ value: "count", label: "Count" },
|
|
1561
|
-
{ value: "percent_empty", label: "% Empty" },
|
|
1562
|
-
{ value: "percent_filled", label: "% Filled" }
|
|
1563
|
-
],
|
|
1564
|
-
date: [
|
|
1565
|
-
{ value: "none", label: "None" },
|
|
1566
|
-
{ value: "count", label: "Count" },
|
|
1567
|
-
{ value: "min", label: "Earliest" },
|
|
1568
|
-
{ value: "max", label: "Latest" },
|
|
1569
|
-
{ value: "range", label: "Date range" },
|
|
1570
|
-
{ value: "percent_empty", label: "% Empty" },
|
|
1571
|
-
{ value: "percent_filled", label: "% Filled" }
|
|
1572
|
-
]
|
|
1573
|
-
};
|
|
1574
|
-
function calculateSummary(column, allData, type, dataType) {
|
|
1575
|
-
if (type === "none") return "";
|
|
1576
|
-
const accessor = column.accessorFn;
|
|
1577
|
-
if (!accessor) return "";
|
|
1578
|
-
const allValues = allData.map((row) => accessor(row, 0)).filter((v) => v !== null && v !== void 0 && v !== "");
|
|
1579
|
-
const totalCount = allData.length;
|
|
1580
|
-
const filledCount = allValues.length;
|
|
1581
|
-
const emptyCount = totalCount - filledCount;
|
|
1582
|
-
switch (type) {
|
|
1583
|
-
case "count":
|
|
1584
|
-
return `Count: ${filledCount.toLocaleString()}`;
|
|
1585
|
-
case "count_unique": {
|
|
1586
|
-
const uniqueValues = new Set(allValues.map((v) => String(v)));
|
|
1587
|
-
return `Unique: ${uniqueValues.size.toLocaleString()}`;
|
|
1588
|
-
}
|
|
1589
|
-
case "percent_empty":
|
|
1590
|
-
return totalCount > 0 ? `Empty: ${(emptyCount / totalCount * 100).toFixed(1)}%` : "Empty: 0%";
|
|
1591
|
-
case "percent_filled":
|
|
1592
|
-
return totalCount > 0 ? `Filled: ${(filledCount / totalCount * 100).toFixed(1)}%` : "Filled: 0%";
|
|
1593
|
-
case "sum":
|
|
1594
|
-
case "average":
|
|
1595
|
-
case "median":
|
|
1596
|
-
case "min":
|
|
1597
|
-
case "max":
|
|
1598
|
-
case "range": {
|
|
1599
|
-
if (dataType === "number") {
|
|
1600
|
-
const numericValues = allValues.map((v) => Number(v)).filter((n) => !Number.isNaN(n));
|
|
1601
|
-
if (numericValues.length === 0) return "\u2014";
|
|
1602
|
-
switch (type) {
|
|
1603
|
-
case "sum": {
|
|
1604
|
-
const sum = numericValues.reduce((a, b) => a + b, 0);
|
|
1605
|
-
return `Sum: ${formatNumber(sum)}`;
|
|
1606
|
-
}
|
|
1607
|
-
case "average": {
|
|
1608
|
-
const avg = numericValues.reduce((a, b) => a + b, 0) / numericValues.length;
|
|
1609
|
-
return `Avg: ${formatNumber(avg)}`;
|
|
1610
|
-
}
|
|
1611
|
-
case "median": {
|
|
1612
|
-
const sorted = [...numericValues].sort((a, b) => a - b);
|
|
1613
|
-
const mid = Math.floor(sorted.length / 2);
|
|
1614
|
-
const median = sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
|
1615
|
-
return `Median: ${formatNumber(median)}`;
|
|
1616
|
-
}
|
|
1617
|
-
case "min":
|
|
1618
|
-
return `Min: ${formatNumber(Math.min(...numericValues))}`;
|
|
1619
|
-
case "max":
|
|
1620
|
-
return `Max: ${formatNumber(Math.max(...numericValues))}`;
|
|
1621
|
-
case "range": {
|
|
1622
|
-
const min = Math.min(...numericValues);
|
|
1623
|
-
const max = Math.max(...numericValues);
|
|
1624
|
-
return `${formatNumber(min)} \u2013 ${formatNumber(max)}`;
|
|
1625
|
-
}
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
if (dataType === "date") {
|
|
1629
|
-
const dateValues = allValues.map((v) => {
|
|
1630
|
-
const d = v instanceof Date ? v : new Date(String(v));
|
|
1631
|
-
return d.getTime();
|
|
1632
|
-
}).filter((t) => !Number.isNaN(t));
|
|
1633
|
-
if (dateValues.length === 0) return "\u2014";
|
|
1634
|
-
switch (type) {
|
|
1635
|
-
case "min":
|
|
1636
|
-
return formatDate(new Date(Math.min(...dateValues)));
|
|
1637
|
-
case "max":
|
|
1638
|
-
return formatDate(new Date(Math.max(...dateValues)));
|
|
1639
|
-
case "range": {
|
|
1640
|
-
const min = new Date(Math.min(...dateValues));
|
|
1641
|
-
const max = new Date(Math.max(...dateValues));
|
|
1642
|
-
return `${formatDate(min)} \u2013 ${formatDate(max)}`;
|
|
1643
|
-
}
|
|
1644
|
-
default:
|
|
1645
|
-
return "\u2014";
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
return "\u2014";
|
|
1649
|
-
}
|
|
1650
|
-
default:
|
|
1651
|
-
return "";
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
function formatNumber(n) {
|
|
1655
|
-
if (Number.isInteger(n)) {
|
|
1656
|
-
return n.toLocaleString();
|
|
1657
|
-
}
|
|
1658
|
-
return n.toLocaleString(void 0, {
|
|
1659
|
-
minimumFractionDigits: 2,
|
|
1660
|
-
maximumFractionDigits: 2
|
|
1661
|
-
});
|
|
1662
|
-
}
|
|
1663
|
-
function DataTableSummary({
|
|
1664
|
-
table,
|
|
1665
|
-
allData,
|
|
1666
|
-
summaryConfig,
|
|
1667
|
-
onSummaryChange,
|
|
1668
|
-
getColumnDataType,
|
|
1669
|
-
gutterWidth = 0,
|
|
1670
|
-
className
|
|
1671
|
-
}) {
|
|
1672
|
-
const visibleColumns = table.getVisibleLeafColumns().filter((col) => col.id !== "select" && col.id !== "actions");
|
|
1673
|
-
const [hoveredColumnId, setHoveredColumnId] = React12.useState(
|
|
1674
|
-
null
|
|
1675
|
-
);
|
|
1676
|
-
const detectDataType = React12.useCallback(
|
|
1677
|
-
(columnId) => {
|
|
1678
|
-
if (getColumnDataType) return getColumnDataType(columnId);
|
|
1679
|
-
const column = table.getColumn(columnId);
|
|
1680
|
-
if (!column) return "text";
|
|
1681
|
-
const meta = column.columnDef.meta;
|
|
1682
|
-
if (meta?.filterType === "number") return "number";
|
|
1683
|
-
if (meta?.filterType === "boolean") return "boolean";
|
|
1684
|
-
const accessor = column.accessorFn;
|
|
1685
|
-
if (!accessor) return "text";
|
|
1686
|
-
for (const row of allData) {
|
|
1687
|
-
const value = accessor(row, 0);
|
|
1688
|
-
if (value === null || value === void 0) continue;
|
|
1689
|
-
if (typeof value === "number") return "number";
|
|
1690
|
-
if (typeof value === "boolean") return "boolean";
|
|
1691
|
-
if (value instanceof Date) return "date";
|
|
1692
|
-
if (typeof value === "string" && !Number.isNaN(Date.parse(value))) {
|
|
1693
|
-
const parsed = new Date(value);
|
|
1694
|
-
if (parsed.getFullYear() > 1900 && parsed.getFullYear() < 2100) {
|
|
1695
|
-
return "date";
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
break;
|
|
1699
|
-
}
|
|
1700
|
-
return "text";
|
|
1701
|
-
},
|
|
1702
|
-
[getColumnDataType, table, allData]
|
|
1703
|
-
);
|
|
1704
|
-
return /* @__PURE__ */ jsxs(
|
|
1705
|
-
TableRow,
|
|
1706
|
-
{
|
|
1707
|
-
className: cn("hover:bg-transparent border-0 bg-transparent", className),
|
|
1708
|
-
children: [
|
|
1709
|
-
gutterWidth > 0 && /* @__PURE__ */ jsx(TableCell, { className: "p-0 border-0", style: { width: gutterWidth } }),
|
|
1710
|
-
visibleColumns.map((column, index) => {
|
|
1711
|
-
const columnId = column.id;
|
|
1712
|
-
const dataType = detectDataType(columnId);
|
|
1713
|
-
const currentType = summaryConfig[columnId] ?? "none";
|
|
1714
|
-
const options = summaryOptions[dataType] ?? summaryOptions.text;
|
|
1715
|
-
const summaryValue = calculateSummary(
|
|
1716
|
-
column,
|
|
1717
|
-
allData,
|
|
1718
|
-
currentType,
|
|
1719
|
-
dataType
|
|
1720
|
-
);
|
|
1721
|
-
const isHovered = hoveredColumnId === columnId;
|
|
1722
|
-
const isLastColumn = index === visibleColumns.length - 1;
|
|
1723
|
-
const isFirstColumn = index === 0;
|
|
1724
|
-
return /* @__PURE__ */ jsx(
|
|
1725
|
-
TableCell,
|
|
1726
|
-
{
|
|
1727
|
-
className: cn(
|
|
1728
|
-
"p-0 border-0",
|
|
1729
|
-
isLastColumn && "rounded-br-md",
|
|
1730
|
-
isFirstColumn && "rounded-bl-md"
|
|
1731
|
-
),
|
|
1732
|
-
style: { width: column.getSize(), minWidth: column.getSize() },
|
|
1733
|
-
children: /* @__PURE__ */ jsx(
|
|
1734
|
-
SummaryCell,
|
|
1735
|
-
{
|
|
1736
|
-
columnId,
|
|
1737
|
-
column,
|
|
1738
|
-
currentType,
|
|
1739
|
-
summaryValue,
|
|
1740
|
-
options,
|
|
1741
|
-
isHovered,
|
|
1742
|
-
onSummaryChange,
|
|
1743
|
-
onMouseEnter: () => setHoveredColumnId(columnId),
|
|
1744
|
-
onMouseLeave: () => setHoveredColumnId(null)
|
|
1745
|
-
}
|
|
1746
|
-
)
|
|
1747
|
-
},
|
|
1748
|
-
columnId
|
|
1749
|
-
);
|
|
1750
|
-
})
|
|
1751
|
-
]
|
|
1752
|
-
}
|
|
1753
|
-
);
|
|
1754
|
-
}
|
|
1755
|
-
function SummaryCell({
|
|
1756
|
-
columnId,
|
|
1757
|
-
currentType,
|
|
1758
|
-
summaryValue,
|
|
1759
|
-
options,
|
|
1760
|
-
isHovered,
|
|
1761
|
-
onSummaryChange,
|
|
1762
|
-
onMouseEnter,
|
|
1763
|
-
onMouseLeave
|
|
1764
|
-
}) {
|
|
1765
|
-
const [isOpen, setIsOpen] = React12.useState(false);
|
|
1766
|
-
const showCalculate = currentType === "none" && (isHovered || isOpen);
|
|
1767
|
-
const context = useDataTableContext();
|
|
1768
|
-
const isCompact = context?.density === "compact";
|
|
1769
|
-
return (
|
|
1770
|
-
// biome-ignore lint/a11y/noStaticElementInteractions: Hover state for visual feedback only
|
|
1771
|
-
/* @__PURE__ */ jsx(
|
|
1772
|
-
"div",
|
|
1773
|
-
{
|
|
1774
|
-
className: cn(
|
|
1775
|
-
"flex items-center min-w-0",
|
|
1776
|
-
isCompact ? "px-1.5 py-0.5" : "px-2 py-1"
|
|
1777
|
-
),
|
|
1778
|
-
onMouseEnter,
|
|
1779
|
-
onMouseLeave,
|
|
1780
|
-
role: "presentation",
|
|
1781
|
-
children: /* @__PURE__ */ jsxs(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
|
|
1782
|
-
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1783
|
-
"button",
|
|
1784
|
-
{
|
|
1785
|
-
type: "button",
|
|
1786
|
-
className: cn(
|
|
1787
|
-
"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",
|
|
1788
|
-
currentType === "none" ? "text-muted-foreground/50 hover:text-muted-foreground" : "text-muted-foreground hover:text-foreground"
|
|
1789
|
-
),
|
|
1790
|
-
children: [
|
|
1791
|
-
currentType === "none" ? /* @__PURE__ */ jsx(
|
|
1792
|
-
"span",
|
|
1793
|
-
{
|
|
1794
|
-
className: cn(
|
|
1795
|
-
"italic transition-opacity",
|
|
1796
|
-
showCalculate ? "opacity-100" : "opacity-0"
|
|
1797
|
-
),
|
|
1798
|
-
children: "Calculate"
|
|
1799
|
-
}
|
|
1800
|
-
) : /* @__PURE__ */ jsx("span", { className: "truncate italic pr-1", children: summaryValue }),
|
|
1801
|
-
/* @__PURE__ */ jsx(
|
|
1802
|
-
ChevronDown,
|
|
1803
|
-
{
|
|
1804
|
-
className: cn(
|
|
1805
|
-
"size-3 shrink-0 transition-opacity",
|
|
1806
|
-
currentType !== "none" ? "opacity-0 group-hover:opacity-50" : "opacity-0"
|
|
1807
|
-
)
|
|
1808
|
-
}
|
|
1809
|
-
)
|
|
1810
|
-
]
|
|
1811
|
-
}
|
|
1812
|
-
) }),
|
|
1813
|
-
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: "w-40", children: options.map((option) => /* @__PURE__ */ jsx(
|
|
1814
|
-
DropdownMenuItem,
|
|
1815
|
-
{
|
|
1816
|
-
onClick: () => onSummaryChange(columnId, option.value),
|
|
1817
|
-
className: cn(
|
|
1818
|
-
"text-xs",
|
|
1819
|
-
currentType === option.value && "bg-accent"
|
|
1820
|
-
),
|
|
1821
|
-
children: option.label
|
|
1822
|
-
},
|
|
1823
|
-
option.value
|
|
1824
|
-
)) })
|
|
1825
|
-
] })
|
|
1826
|
-
}
|
|
1827
|
-
)
|
|
1828
|
-
);
|
|
1829
|
-
}
|
|
1830
|
-
function DataTableSearch({
|
|
1831
|
-
searchValue = "",
|
|
1832
|
-
searchPlaceholder = "Search...",
|
|
1833
|
-
onSearchChange,
|
|
1834
|
-
className
|
|
1835
|
-
}) {
|
|
1836
|
-
const context = useDataTableContext();
|
|
1837
|
-
const fontSizeClass = context?.fontSizeClass ?? "text-xs";
|
|
1838
|
-
const [isExpanded, setIsExpanded] = React12.useState(false);
|
|
1839
|
-
const inputRef = React12.useRef(null);
|
|
1840
|
-
React12.useEffect(() => {
|
|
1841
|
-
if (searchValue && !isExpanded) {
|
|
1842
|
-
setIsExpanded(true);
|
|
1843
|
-
}
|
|
1844
|
-
}, [searchValue, isExpanded]);
|
|
1845
|
-
React12.useEffect(() => {
|
|
1846
|
-
if (isExpanded && inputRef.current) {
|
|
1847
|
-
inputRef.current.focus();
|
|
1848
|
-
}
|
|
1849
|
-
}, [isExpanded]);
|
|
1850
|
-
const handleBlur = () => {
|
|
1851
|
-
if (!searchValue) {
|
|
1852
|
-
setIsExpanded(false);
|
|
1853
|
-
}
|
|
1854
|
-
};
|
|
1855
|
-
const handleClear = () => {
|
|
1856
|
-
onSearchChange?.("");
|
|
1857
|
-
setIsExpanded(false);
|
|
1858
|
-
};
|
|
1859
|
-
return /* @__PURE__ */ jsx("div", { className: cn("relative flex items-center", className), children: /* @__PURE__ */ jsxs(
|
|
1860
|
-
"div",
|
|
1861
|
-
{
|
|
1862
|
-
className: cn(
|
|
1863
|
-
"flex items-center rounded-md border border-transparent transition-all duration-200 ease-out",
|
|
1864
|
-
isExpanded ? "w-48 border-input bg-background" : "w-8 cursor-pointer"
|
|
1865
|
-
),
|
|
1866
|
-
children: [
|
|
1867
|
-
/* @__PURE__ */ jsx(
|
|
1868
|
-
"button",
|
|
1869
|
-
{
|
|
1870
|
-
type: "button",
|
|
1871
|
-
onClick: () => !isExpanded && setIsExpanded(true),
|
|
1872
|
-
className: cn(
|
|
1873
|
-
"flex items-center justify-center shrink-0 transition-colors rounded-md",
|
|
1874
|
-
dataTableTopperIconClasses,
|
|
1875
|
-
isExpanded ? "size-8 cursor-default" : "size-8"
|
|
1876
|
-
),
|
|
1877
|
-
"aria-label": isExpanded ? void 0 : "Search",
|
|
1878
|
-
children: /* @__PURE__ */ jsx(Search, { className: "size-4" })
|
|
1879
|
-
}
|
|
1880
|
-
),
|
|
1881
|
-
/* @__PURE__ */ jsx(
|
|
1882
|
-
"input",
|
|
1883
|
-
{
|
|
1884
|
-
ref: inputRef,
|
|
1885
|
-
type: "text",
|
|
1886
|
-
placeholder: searchPlaceholder,
|
|
1887
|
-
value: searchValue,
|
|
1888
|
-
onChange: (e) => onSearchChange?.(e.target.value),
|
|
1889
|
-
onBlur: handleBlur,
|
|
1890
|
-
className: cn(
|
|
1891
|
-
"h-8 bg-transparent outline-none placeholder:text-muted-foreground transition-all duration-200",
|
|
1892
|
-
fontSizeClass,
|
|
1893
|
-
isExpanded ? "w-full pr-7 opacity-100" : "w-0 opacity-0"
|
|
1894
|
-
)
|
|
1895
|
-
}
|
|
1896
|
-
),
|
|
1897
|
-
isExpanded && searchValue && /* @__PURE__ */ jsx(
|
|
1898
|
-
"button",
|
|
1899
|
-
{
|
|
1900
|
-
type: "button",
|
|
1901
|
-
onClick: handleClear,
|
|
1902
|
-
className: "absolute right-1.5 flex items-center justify-center size-5 rounded-sm hover:bg-accent/50",
|
|
1903
|
-
"aria-label": "Clear search",
|
|
1904
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-3.5 text-muted-foreground" })
|
|
1905
|
-
}
|
|
1906
|
-
)
|
|
1907
|
-
]
|
|
1908
|
-
}
|
|
1909
|
-
) });
|
|
1910
|
-
}
|
|
1911
|
-
function DataTableToolbar({
|
|
1912
|
-
searchValue = "",
|
|
1913
|
-
searchPlaceholder = "Search...",
|
|
1914
|
-
onSearchChange,
|
|
1915
|
-
className,
|
|
1916
|
-
children,
|
|
1917
|
-
...props
|
|
1918
|
-
}) {
|
|
1919
|
-
return /* @__PURE__ */ jsxs(
|
|
1920
|
-
"div",
|
|
1921
|
-
{
|
|
1922
|
-
role: "toolbar",
|
|
1923
|
-
"aria-orientation": "horizontal",
|
|
1924
|
-
className: cn(
|
|
1925
|
-
"flex w-full items-center justify-end gap-1 px-1",
|
|
1926
|
-
className
|
|
1927
|
-
),
|
|
1928
|
-
...props,
|
|
1929
|
-
children: [
|
|
1930
|
-
onSearchChange && /* @__PURE__ */ jsx(
|
|
1931
|
-
DataTableSearch,
|
|
1932
|
-
{
|
|
1933
|
-
searchValue,
|
|
1934
|
-
searchPlaceholder,
|
|
1935
|
-
onSearchChange
|
|
1936
|
-
}
|
|
1937
|
-
),
|
|
1938
|
-
children
|
|
1939
|
-
]
|
|
1940
|
-
}
|
|
1941
|
-
);
|
|
1942
|
-
}
|
|
1943
|
-
function DataTableTopper({
|
|
1944
|
-
tabs,
|
|
1945
|
-
activeTab,
|
|
1946
|
-
onTabChange,
|
|
1947
|
-
gutterWidth = 0,
|
|
1948
|
-
className,
|
|
1949
|
-
children,
|
|
1950
|
-
...props
|
|
1951
|
-
}) {
|
|
1952
|
-
return /* @__PURE__ */ jsx(
|
|
1953
|
-
"div",
|
|
1954
|
-
{
|
|
1955
|
-
className: cn(
|
|
1956
|
-
// Container context for responsive layout based on available width
|
|
1957
|
-
"@container w-full min-w-0 shrink-0",
|
|
1958
|
-
// Visual styling
|
|
1959
|
-
"border-b border-border/40 pb-1",
|
|
1960
|
-
className
|
|
1961
|
-
),
|
|
1962
|
-
...props,
|
|
1963
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-row items-center justify-between gap-3", children: [
|
|
1964
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 shrink-0 items-center gap-0.5", children: [
|
|
1965
|
-
gutterWidth > 0 && /* @__PURE__ */ jsx("div", { className: "shrink-0", style: { width: gutterWidth } }),
|
|
1966
|
-
tabs && tabs.length > 0 && /* @__PURE__ */ jsx("div", { className: "block @min-[450px]:hidden", children: /* @__PURE__ */ jsxs(Select, { value: activeTab, onValueChange: onTabChange, children: [
|
|
1967
|
-
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-7 w-[100px] text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select tab" }) }),
|
|
1968
|
-
/* @__PURE__ */ jsx(SelectContent, { children: tabs.map((tab) => /* @__PURE__ */ jsx(SelectItem, { value: tab.id, children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
1969
|
-
tab.label,
|
|
1970
|
-
tab.count !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: tab.count })
|
|
1971
|
-
] }) }, tab.id)) })
|
|
1972
|
-
] }) }),
|
|
1973
|
-
/* @__PURE__ */ jsx(
|
|
1974
|
-
"div",
|
|
1975
|
-
{
|
|
1976
|
-
className: cn(
|
|
1977
|
-
"items-center gap-0.5 overflow-x-auto no-scrollbar",
|
|
1978
|
-
tabs && tabs.length > 0 ? "hidden @min-[450px]:flex" : "flex"
|
|
1979
|
-
),
|
|
1980
|
-
children: tabs?.map((tab) => /* @__PURE__ */ jsxs(
|
|
1981
|
-
"button",
|
|
1982
|
-
{
|
|
1983
|
-
type: "button",
|
|
1984
|
-
onClick: () => onTabChange?.(tab.id),
|
|
1985
|
-
className: cn(
|
|
1986
|
-
"relative flex items-center gap-1.5 px-2 py-1 text-sm transition-colors rounded-md whitespace-nowrap",
|
|
1987
|
-
activeTab === tab.id ? "text-foreground font-medium" : "text-muted-foreground hover:text-foreground hover:bg-accent/50"
|
|
1988
|
-
),
|
|
1989
|
-
children: [
|
|
1990
|
-
tab.label,
|
|
1991
|
-
tab.count !== void 0 && /* @__PURE__ */ jsx(
|
|
1992
|
-
"span",
|
|
1993
|
-
{
|
|
1994
|
-
className: cn(
|
|
1995
|
-
"text-xs tabular-nums",
|
|
1996
|
-
activeTab === tab.id ? "text-muted-foreground" : "text-muted-foreground/60"
|
|
1997
|
-
),
|
|
1998
|
-
children: tab.count
|
|
1999
|
-
}
|
|
2000
|
-
),
|
|
2001
|
-
activeTab === tab.id && /* @__PURE__ */ jsx("span", { className: "absolute bottom-0 left-2 right-2 h-0.5 bg-foreground rounded-full" })
|
|
2002
|
-
]
|
|
2003
|
-
},
|
|
2004
|
-
tab.id
|
|
2005
|
-
))
|
|
2006
|
-
}
|
|
2007
|
-
)
|
|
2008
|
-
] }),
|
|
2009
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children })
|
|
2010
|
-
] })
|
|
2011
|
-
}
|
|
2012
|
-
);
|
|
2013
|
-
}
|
|
2014
|
-
function getColumnDisplayName(column) {
|
|
2015
|
-
const meta = column.columnDef.meta;
|
|
2016
|
-
if (meta?.displayName) {
|
|
2017
|
-
return meta.displayName;
|
|
2018
|
-
}
|
|
2019
|
-
if (typeof column.columnDef.header === "string") {
|
|
2020
|
-
return column.columnDef.header;
|
|
2021
|
-
}
|
|
2022
|
-
return column.id;
|
|
2023
|
-
}
|
|
2024
|
-
function DataTableViewOptions({
|
|
2025
|
-
table
|
|
2026
|
-
}) {
|
|
2027
|
-
const context = useDataTableContext();
|
|
2028
|
-
const fontSizeClass = context?.fontSizeClass ?? "text-xs";
|
|
2029
|
-
const [draggedId, setDraggedId] = React12.useState(null);
|
|
2030
|
-
const [dragOverId, setDragOverId] = React12.useState(null);
|
|
2031
|
-
const columns = React12.useMemo(
|
|
2032
|
-
() => table.getAllColumns().filter(
|
|
2033
|
-
(column) => typeof column.accessorFn !== "undefined" && column.getCanHide()
|
|
2034
|
-
),
|
|
2035
|
-
[table]
|
|
2036
|
-
);
|
|
2037
|
-
const columnOrder = table.getState().columnOrder;
|
|
2038
|
-
const orderedColumns = React12.useMemo(() => {
|
|
2039
|
-
if (!columnOrder || columnOrder.length === 0) {
|
|
2040
|
-
return columns;
|
|
2041
|
-
}
|
|
2042
|
-
return [...columns].sort((a, b) => {
|
|
2043
|
-
const aIndex = columnOrder.indexOf(a.id);
|
|
2044
|
-
const bIndex = columnOrder.indexOf(b.id);
|
|
2045
|
-
if (aIndex === -1 && bIndex === -1) return 0;
|
|
2046
|
-
if (aIndex === -1) return 1;
|
|
2047
|
-
if (bIndex === -1) return -1;
|
|
2048
|
-
return aIndex - bIndex;
|
|
2049
|
-
});
|
|
2050
|
-
}, [columns, columnOrder]);
|
|
2051
|
-
const handleDragStart = (e, columnId) => {
|
|
2052
|
-
setDraggedId(columnId);
|
|
2053
|
-
e.dataTransfer.effectAllowed = "move";
|
|
2054
|
-
e.dataTransfer.setData("text/plain", columnId);
|
|
2055
|
-
};
|
|
2056
|
-
const handleDragOver = (e, columnId) => {
|
|
2057
|
-
e.preventDefault();
|
|
2058
|
-
if (draggedId && draggedId !== columnId) {
|
|
2059
|
-
setDragOverId(columnId);
|
|
2060
|
-
}
|
|
2061
|
-
};
|
|
2062
|
-
const handleDragLeave = () => {
|
|
2063
|
-
setDragOverId(null);
|
|
2064
|
-
};
|
|
2065
|
-
const handleDrop = (e, targetColumnId) => {
|
|
2066
|
-
e.preventDefault();
|
|
2067
|
-
if (!draggedId || draggedId === targetColumnId) {
|
|
2068
|
-
setDraggedId(null);
|
|
2069
|
-
setDragOverId(null);
|
|
2070
|
-
return;
|
|
2071
|
-
}
|
|
2072
|
-
const allColumnIds = table.getAllColumns().map((c) => c.id);
|
|
2073
|
-
const currentOrder = columnOrder && columnOrder.length > 0 ? [...columnOrder] : [...allColumnIds];
|
|
2074
|
-
const draggedIndex = currentOrder.indexOf(draggedId);
|
|
2075
|
-
const targetIndex = currentOrder.indexOf(targetColumnId);
|
|
2076
|
-
if (draggedIndex === -1 || targetIndex === -1) {
|
|
2077
|
-
setDraggedId(null);
|
|
2078
|
-
setDragOverId(null);
|
|
2079
|
-
return;
|
|
2080
|
-
}
|
|
2081
|
-
currentOrder.splice(draggedIndex, 1);
|
|
2082
|
-
currentOrder.splice(targetIndex, 0, draggedId);
|
|
2083
|
-
table.setColumnOrder(currentOrder);
|
|
2084
|
-
setDraggedId(null);
|
|
2085
|
-
setDragOverId(null);
|
|
2086
|
-
};
|
|
2087
|
-
const handleDragEnd = () => {
|
|
2088
|
-
setDraggedId(null);
|
|
2089
|
-
setDragOverId(null);
|
|
2090
|
-
};
|
|
2091
|
-
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
2092
|
-
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
2093
|
-
Button,
|
|
2094
|
-
{
|
|
2095
|
-
...dataTableTopperButtonProps,
|
|
2096
|
-
"aria-label": "View columns",
|
|
2097
|
-
className: dataTableTopperOpenStateClasses,
|
|
2098
|
-
children: /* @__PURE__ */ jsx(Settings2, { className: "size-4" })
|
|
2099
|
-
}
|
|
2100
|
-
) }),
|
|
2101
|
-
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-52", children: [
|
|
2102
|
-
/* @__PURE__ */ jsx(
|
|
2103
|
-
DropdownMenuLabel,
|
|
2104
|
-
{
|
|
2105
|
-
className: cn("font-normal text-muted-foreground", fontSizeClass),
|
|
2106
|
-
children: "View Columns"
|
|
2107
|
-
}
|
|
2108
|
-
),
|
|
2109
|
-
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
2110
|
-
/* @__PURE__ */ jsx("div", { role: "list", className: "max-h-64 overflow-y-auto", children: orderedColumns.map((column) => {
|
|
2111
|
-
const label = getColumnDisplayName(column);
|
|
2112
|
-
const isVisible = column.getIsVisible();
|
|
2113
|
-
const isDragging = draggedId === column.id;
|
|
2114
|
-
const isDragOver = dragOverId === column.id;
|
|
2115
|
-
return (
|
|
2116
|
-
// biome-ignore lint/a11y/useSemanticElements: Using div with role for dropdown menu compatibility
|
|
2117
|
-
/* @__PURE__ */ jsxs(
|
|
2118
|
-
"div",
|
|
2119
|
-
{
|
|
2120
|
-
role: "listitem",
|
|
2121
|
-
draggable: true,
|
|
2122
|
-
onDragStart: (e) => handleDragStart(e, column.id),
|
|
2123
|
-
onDragOver: (e) => handleDragOver(e, column.id),
|
|
2124
|
-
onDragLeave: handleDragLeave,
|
|
2125
|
-
onDrop: (e) => handleDrop(e, column.id),
|
|
2126
|
-
onDragEnd: handleDragEnd,
|
|
2127
|
-
className: cn(
|
|
2128
|
-
"flex items-center gap-2 px-2 py-1.5 rounded-sm cursor-default",
|
|
2129
|
-
fontSizeClass,
|
|
2130
|
-
"hover:bg-accent hover:text-accent-foreground",
|
|
2131
|
-
isDragging && "opacity-50",
|
|
2132
|
-
isDragOver && "bg-accent/50"
|
|
2133
|
-
),
|
|
2134
|
-
children: [
|
|
2135
|
-
/* @__PURE__ */ jsx(
|
|
2136
|
-
"div",
|
|
2137
|
-
{
|
|
2138
|
-
className: cn(
|
|
2139
|
-
"flex items-center justify-center size-5 cursor-grab active:cursor-grabbing shrink-0",
|
|
2140
|
-
dataTableTopperIconClasses
|
|
2141
|
-
),
|
|
2142
|
-
children: /* @__PURE__ */ jsx(GripVertical, { className: "size-3.5" })
|
|
2143
|
-
}
|
|
2144
|
-
),
|
|
2145
|
-
/* @__PURE__ */ jsx(
|
|
2146
|
-
"span",
|
|
2147
|
-
{
|
|
2148
|
-
className: cn(
|
|
2149
|
-
"flex-1",
|
|
2150
|
-
!isVisible && "text-muted-foreground"
|
|
2151
|
-
),
|
|
2152
|
-
children: label
|
|
2153
|
-
}
|
|
2154
|
-
),
|
|
2155
|
-
/* @__PURE__ */ jsx(
|
|
2156
|
-
"button",
|
|
2157
|
-
{
|
|
2158
|
-
type: "button",
|
|
2159
|
-
onClick: () => column.toggleVisibility(!isVisible),
|
|
2160
|
-
className: cn(
|
|
2161
|
-
"flex items-center justify-center size-5 rounded-sm shrink-0",
|
|
2162
|
-
dataTableTopperIconClasses
|
|
2163
|
-
),
|
|
2164
|
-
"aria-label": isVisible ? "Hide column" : "Show column",
|
|
2165
|
-
children: isVisible ? /* @__PURE__ */ jsx(Eye, { className: "size-3.5" }) : /* @__PURE__ */ jsx(EyeOff, { className: "size-3.5" })
|
|
2166
|
-
}
|
|
2167
|
-
)
|
|
2168
|
-
]
|
|
2169
|
-
},
|
|
2170
|
-
column.id
|
|
2171
|
-
)
|
|
2172
|
-
);
|
|
2173
|
-
}) })
|
|
2174
|
-
] })
|
|
2175
|
-
] });
|
|
2176
|
-
}
|
|
2177
|
-
function hasUnsavedChanges(currentState, activeView) {
|
|
2178
|
-
if (!activeView) return false;
|
|
2179
|
-
const visA = JSON.stringify(currentState.columnVisibility ?? {});
|
|
2180
|
-
const visB = JSON.stringify(activeView.columnVisibility ?? {});
|
|
2181
|
-
if (visA !== visB) return true;
|
|
2182
|
-
const filtA = JSON.stringify(currentState.filters ?? []);
|
|
2183
|
-
const filtB = JSON.stringify(activeView.filters ?? []);
|
|
2184
|
-
if (filtA !== filtB) return true;
|
|
2185
|
-
const sortA = JSON.stringify(currentState.sorting ?? []);
|
|
2186
|
-
const sortB = JSON.stringify(activeView.sorting ?? []);
|
|
2187
|
-
if (sortA !== sortB) return true;
|
|
2188
|
-
const orderA = JSON.stringify(currentState.columnOrder ?? []);
|
|
2189
|
-
const orderB = JSON.stringify(activeView.columnOrder ?? []);
|
|
2190
|
-
if (orderA !== orderB) return true;
|
|
2191
|
-
const wrapA = JSON.stringify(currentState.columnWrapping ?? {});
|
|
2192
|
-
const wrapB = JSON.stringify(activeView.columnWrapping ?? {});
|
|
2193
|
-
if (wrapA !== wrapB) return true;
|
|
2194
|
-
const rowA = JSON.stringify(currentState.rowOrder ?? []);
|
|
2195
|
-
const rowB = JSON.stringify(activeView.rowOrder ?? []);
|
|
2196
|
-
if (rowA !== rowB) return true;
|
|
2197
|
-
return false;
|
|
2198
|
-
}
|
|
2199
|
-
function DataTableViews({
|
|
2200
|
-
views,
|
|
2201
|
-
activeViewId,
|
|
2202
|
-
currentState,
|
|
2203
|
-
onSelectView,
|
|
2204
|
-
onSaveView,
|
|
2205
|
-
onUpdateView,
|
|
2206
|
-
onDeleteView,
|
|
2207
|
-
onSetDefaultView,
|
|
2208
|
-
className
|
|
2209
|
-
}) {
|
|
2210
|
-
const context = useDataTableContext();
|
|
2211
|
-
const fontSizeClass = context?.fontSizeClass ?? "text-xs";
|
|
2212
|
-
const [saveDialogOpen, setSaveDialogOpen] = React12.useState(false);
|
|
2213
|
-
const [newViewName, setNewViewName] = React12.useState("");
|
|
2214
|
-
const [setAsDefault, setSetAsDefault] = React12.useState(false);
|
|
2215
|
-
const [nameError, setNameError] = React12.useState(null);
|
|
2216
|
-
const activeView = views.find((v) => v.id === activeViewId);
|
|
2217
|
-
views.find((v) => v.isDefault);
|
|
2218
|
-
const hasChanges = hasUnsavedChanges(currentState, activeView);
|
|
2219
|
-
const checkDuplicateName = (name) => {
|
|
2220
|
-
const trimmedName = name.trim();
|
|
2221
|
-
if (!trimmedName) {
|
|
2222
|
-
setNameError(null);
|
|
2223
|
-
return;
|
|
2224
|
-
}
|
|
2225
|
-
const isDuplicate = views.some(
|
|
2226
|
-
(v) => v.name.toLowerCase() === trimmedName.toLowerCase()
|
|
2227
|
-
);
|
|
2228
|
-
setNameError(isDuplicate ? "A view with this name already exists" : null);
|
|
2229
|
-
};
|
|
2230
|
-
const handleSaveNewView = () => {
|
|
2231
|
-
if (!newViewName.trim()) return;
|
|
2232
|
-
const trimmedName = newViewName.trim();
|
|
2233
|
-
const isDuplicate = views.some(
|
|
2234
|
-
(v) => v.name.toLowerCase() === trimmedName.toLowerCase()
|
|
2235
|
-
);
|
|
2236
|
-
if (isDuplicate) {
|
|
2237
|
-
setNameError("A view with this name already exists");
|
|
2238
|
-
return;
|
|
2239
|
-
}
|
|
2240
|
-
if (onSaveView) {
|
|
2241
|
-
onSaveView({
|
|
2242
|
-
name: trimmedName,
|
|
2243
|
-
columnVisibility: currentState.columnVisibility,
|
|
2244
|
-
columnOrder: currentState.columnOrder,
|
|
2245
|
-
filters: currentState.filters,
|
|
2246
|
-
sorting: currentState.sorting,
|
|
2247
|
-
isDefault: setAsDefault
|
|
2248
|
-
});
|
|
2249
|
-
}
|
|
2250
|
-
setNewViewName("");
|
|
2251
|
-
setSetAsDefault(false);
|
|
2252
|
-
setNameError(null);
|
|
2253
|
-
setSaveDialogOpen(false);
|
|
2254
|
-
};
|
|
2255
|
-
const handleUpdateCurrentView = () => {
|
|
2256
|
-
if (!activeViewId || !onUpdateView) return;
|
|
2257
|
-
onUpdateView(activeViewId, {
|
|
2258
|
-
columnVisibility: currentState.columnVisibility,
|
|
2259
|
-
columnOrder: currentState.columnOrder,
|
|
2260
|
-
filters: currentState.filters,
|
|
2261
|
-
sorting: currentState.sorting,
|
|
2262
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2263
|
-
});
|
|
2264
|
-
};
|
|
2265
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2266
|
-
/* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-1", className), children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
2267
|
-
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
2268
|
-
Button,
|
|
2269
|
-
{
|
|
2270
|
-
...dataTableTopperButtonProps,
|
|
2271
|
-
className: cn(
|
|
2272
|
-
fontSizeClass,
|
|
2273
|
-
dataTableTopperOpenStateClasses,
|
|
2274
|
-
dataTableTopperResponsiveClasses
|
|
2275
|
-
),
|
|
2276
|
-
children: [
|
|
2277
|
-
/* @__PURE__ */ jsx(LayoutGrid, { className: "size-4" }),
|
|
2278
|
-
/* @__PURE__ */ jsx("span", { className: "hidden @min-[450px]:inline", children: activeView?.name ?? "Default View" })
|
|
2279
|
-
]
|
|
2280
|
-
}
|
|
2281
|
-
) }),
|
|
2282
|
-
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", className: "w-56", children: [
|
|
2283
|
-
views.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2284
|
-
views.map((view) => /* @__PURE__ */ jsxs(
|
|
2285
|
-
"div",
|
|
2286
|
-
{
|
|
2287
|
-
className: "group relative flex items-center",
|
|
2288
|
-
children: [
|
|
2289
|
-
/* @__PURE__ */ jsxs(
|
|
2290
|
-
DropdownMenuItem,
|
|
2291
|
-
{
|
|
2292
|
-
onClick: () => onSelectView(view),
|
|
2293
|
-
className: cn(
|
|
2294
|
-
"flex-1 flex items-center justify-between pr-16",
|
|
2295
|
-
fontSizeClass
|
|
2296
|
-
),
|
|
2297
|
-
children: [
|
|
2298
|
-
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
2299
|
-
view.isDefault && /* @__PURE__ */ jsx(Star, { className: "size-3 fill-yellow-400 text-yellow-400" }),
|
|
2300
|
-
/* @__PURE__ */ jsx("span", { children: view.name })
|
|
2301
|
-
] }),
|
|
2302
|
-
activeViewId === view.id && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" })
|
|
2303
|
-
]
|
|
2304
|
-
}
|
|
2305
|
-
),
|
|
2306
|
-
/* @__PURE__ */ jsxs("div", { className: "absolute right-2 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
|
|
2307
|
-
!view.isDefault && onSetDefaultView && /* @__PURE__ */ jsx(
|
|
2308
|
-
"button",
|
|
2309
|
-
{
|
|
2310
|
-
type: "button",
|
|
2311
|
-
onClick: (e) => {
|
|
2312
|
-
e.stopPropagation();
|
|
2313
|
-
onSetDefaultView(view.id);
|
|
2314
|
-
},
|
|
2315
|
-
className: "p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground",
|
|
2316
|
-
title: "Set as default",
|
|
2317
|
-
children: /* @__PURE__ */ jsx(Star, { className: "size-3" })
|
|
2318
|
-
}
|
|
2319
|
-
),
|
|
2320
|
-
views.length > 1 && onDeleteView && /* @__PURE__ */ jsx(
|
|
2321
|
-
"button",
|
|
2322
|
-
{
|
|
2323
|
-
type: "button",
|
|
2324
|
-
onClick: (e) => {
|
|
2325
|
-
e.stopPropagation();
|
|
2326
|
-
onDeleteView(view.id);
|
|
2327
|
-
},
|
|
2328
|
-
className: "p-1 rounded hover:bg-accent text-muted-foreground hover:text-destructive",
|
|
2329
|
-
title: "Delete view",
|
|
2330
|
-
children: /* @__PURE__ */ jsx(Trash2, { className: "size-3" })
|
|
2331
|
-
}
|
|
2332
|
-
)
|
|
2333
|
-
] })
|
|
2334
|
-
]
|
|
2335
|
-
},
|
|
2336
|
-
view.id
|
|
2337
|
-
)),
|
|
2338
|
-
/* @__PURE__ */ jsx(DropdownMenuSeparator, {})
|
|
2339
|
-
] }) : null,
|
|
2340
|
-
onUpdateView && hasChanges && activeView && /* @__PURE__ */ jsxs(
|
|
2341
|
-
DropdownMenuItem,
|
|
2342
|
-
{
|
|
2343
|
-
onClick: handleUpdateCurrentView,
|
|
2344
|
-
className: fontSizeClass,
|
|
2345
|
-
children: [
|
|
2346
|
-
/* @__PURE__ */ jsx(Save, { className: "mr-2 size-3.5" }),
|
|
2347
|
-
"Save changes"
|
|
2348
|
-
]
|
|
2349
|
-
}
|
|
2350
|
-
),
|
|
2351
|
-
onSaveView && /* @__PURE__ */ jsxs(
|
|
2352
|
-
DropdownMenuItem,
|
|
2353
|
-
{
|
|
2354
|
-
onClick: () => setSaveDialogOpen(true),
|
|
2355
|
-
className: fontSizeClass,
|
|
2356
|
-
children: [
|
|
2357
|
-
/* @__PURE__ */ jsx(Plus, { className: "mr-2 size-3.5" }),
|
|
2358
|
-
"Save as new view"
|
|
2359
|
-
]
|
|
2360
|
-
}
|
|
2361
|
-
)
|
|
2362
|
-
] })
|
|
2363
|
-
] }) }),
|
|
2364
|
-
/* @__PURE__ */ jsx(
|
|
2365
|
-
Dialog,
|
|
2366
|
-
{
|
|
2367
|
-
open: saveDialogOpen,
|
|
2368
|
-
onOpenChange: (open) => {
|
|
2369
|
-
setSaveDialogOpen(open);
|
|
2370
|
-
if (!open) {
|
|
2371
|
-
setNewViewName("");
|
|
2372
|
-
setSetAsDefault(false);
|
|
2373
|
-
setNameError(null);
|
|
2374
|
-
}
|
|
2375
|
-
},
|
|
2376
|
-
children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
2377
|
-
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2378
|
-
/* @__PURE__ */ jsx(DialogTitle, { children: "Save View" }),
|
|
2379
|
-
/* @__PURE__ */ jsx(DialogDescription, { children: "Save your current table configuration as a reusable view." })
|
|
2380
|
-
] }),
|
|
2381
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-4 py-4", children: [
|
|
2382
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
2383
|
-
/* @__PURE__ */ jsx(Label, { htmlFor: "view-name", children: "View name" }),
|
|
2384
|
-
/* @__PURE__ */ jsx(
|
|
2385
|
-
Input,
|
|
2386
|
-
{
|
|
2387
|
-
id: "view-name",
|
|
2388
|
-
placeholder: "e.g., Active Users, Recent Signups",
|
|
2389
|
-
value: newViewName,
|
|
2390
|
-
onChange: (e) => {
|
|
2391
|
-
setNewViewName(e.target.value);
|
|
2392
|
-
checkDuplicateName(e.target.value);
|
|
2393
|
-
},
|
|
2394
|
-
onKeyDown: (e) => {
|
|
2395
|
-
if (e.key === "Enter") handleSaveNewView();
|
|
2396
|
-
},
|
|
2397
|
-
className: nameError ? "border-destructive" : "",
|
|
2398
|
-
autoFocus: true
|
|
2399
|
-
}
|
|
2400
|
-
),
|
|
2401
|
-
nameError && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: nameError })
|
|
2402
|
-
] }),
|
|
2403
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2404
|
-
/* @__PURE__ */ jsx(
|
|
2405
|
-
"input",
|
|
2406
|
-
{
|
|
2407
|
-
type: "checkbox",
|
|
2408
|
-
id: "set-default",
|
|
2409
|
-
checked: setAsDefault,
|
|
2410
|
-
onChange: (e) => setSetAsDefault(e.target.checked),
|
|
2411
|
-
className: "size-4 rounded border-muted-foreground/30"
|
|
2412
|
-
}
|
|
2413
|
-
),
|
|
2414
|
-
/* @__PURE__ */ jsx(
|
|
2415
|
-
Label,
|
|
2416
|
-
{
|
|
2417
|
-
htmlFor: "set-default",
|
|
2418
|
-
className: "text-sm font-normal cursor-pointer",
|
|
2419
|
-
children: "Set as default view"
|
|
2420
|
-
}
|
|
2421
|
-
)
|
|
2422
|
-
] })
|
|
2423
|
-
] }),
|
|
2424
|
-
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
2425
|
-
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setSaveDialogOpen(false), children: "Cancel" }),
|
|
2426
|
-
/* @__PURE__ */ jsx(
|
|
2427
|
-
Button,
|
|
2428
|
-
{
|
|
2429
|
-
onClick: handleSaveNewView,
|
|
2430
|
-
disabled: !newViewName.trim() || !!nameError,
|
|
2431
|
-
children: "Save View"
|
|
2432
|
-
}
|
|
2433
|
-
)
|
|
2434
|
-
] })
|
|
2435
|
-
] })
|
|
2436
|
-
}
|
|
2437
|
-
)
|
|
2438
|
-
] });
|
|
2439
|
-
}
|
|
2440
|
-
function Command({
|
|
2441
|
-
className,
|
|
2442
|
-
...props
|
|
2443
|
-
}) {
|
|
2444
|
-
return /* @__PURE__ */ jsx(
|
|
2445
|
-
Command$1,
|
|
2446
|
-
{
|
|
2447
|
-
className: cn(
|
|
2448
|
-
"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-box",
|
|
2449
|
-
className
|
|
2450
|
-
),
|
|
2451
|
-
...props
|
|
2452
|
-
}
|
|
2453
|
-
);
|
|
2454
|
-
}
|
|
2455
|
-
function CommandDialog({
|
|
2456
|
-
children,
|
|
2457
|
-
title = "Command palette",
|
|
2458
|
-
...props
|
|
2459
|
-
}) {
|
|
2460
|
-
return /* @__PURE__ */ jsx(Dialog, { ...props, children: /* @__PURE__ */ jsxs(DialogContent, { className: "overflow-hidden p-0", children: [
|
|
2461
|
-
/* @__PURE__ */ jsx(DialogTitle, { className: "sr-only", children: title }),
|
|
2462
|
-
/* @__PURE__ */ jsx(Command, { className: "[&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5", children })
|
|
2463
|
-
] }) });
|
|
2464
|
-
}
|
|
2465
|
-
function CommandInput({
|
|
2466
|
-
className,
|
|
2467
|
-
...props
|
|
2468
|
-
}) {
|
|
2469
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex items-center border-b px-3", "cmdk-input-wrapper": "", children: [
|
|
2470
|
-
/* @__PURE__ */ jsx(Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
|
|
2471
|
-
/* @__PURE__ */ jsx(
|
|
2472
|
-
Command$1.Input,
|
|
2473
|
-
{
|
|
2474
|
-
className: cn(
|
|
2475
|
-
"placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-10 w-full rounded-box bg-transparent py-3 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
2476
|
-
className
|
|
2477
|
-
),
|
|
2478
|
-
...props
|
|
2479
|
-
}
|
|
2480
|
-
)
|
|
2481
|
-
] });
|
|
2482
|
-
}
|
|
2483
|
-
function CommandList({
|
|
2484
|
-
className,
|
|
2485
|
-
...props
|
|
2486
|
-
}) {
|
|
2487
|
-
return /* @__PURE__ */ jsx(
|
|
2488
|
-
Command$1.List,
|
|
2489
|
-
{
|
|
2490
|
-
className: cn(
|
|
2491
|
-
"max-h-[300px] overflow-y-auto overflow-x-hidden scroll-py-1",
|
|
2492
|
-
className
|
|
2493
|
-
),
|
|
2494
|
-
...props
|
|
2495
|
-
}
|
|
2496
|
-
);
|
|
2497
|
-
}
|
|
2498
|
-
function CommandEmpty({
|
|
2499
|
-
className,
|
|
2500
|
-
...props
|
|
2501
|
-
}) {
|
|
2502
|
-
return /* @__PURE__ */ jsx(
|
|
2503
|
-
Command$1.Empty,
|
|
2504
|
-
{
|
|
2505
|
-
className: cn("py-6 text-center text-sm", className),
|
|
2506
|
-
...props
|
|
2507
|
-
}
|
|
2508
|
-
);
|
|
2509
|
-
}
|
|
2510
|
-
function CommandGroup({
|
|
2511
|
-
className,
|
|
2512
|
-
...props
|
|
2513
|
-
}) {
|
|
2514
|
-
return /* @__PURE__ */ jsx(
|
|
2515
|
-
Command$1.Group,
|
|
2516
|
-
{
|
|
2517
|
-
className: cn(
|
|
2518
|
-
"text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
|
|
2519
|
-
className
|
|
2520
|
-
),
|
|
2521
|
-
...props
|
|
2522
|
-
}
|
|
2523
|
-
);
|
|
2524
|
-
}
|
|
2525
|
-
function CommandSeparator({
|
|
2526
|
-
className,
|
|
2527
|
-
...props
|
|
2528
|
-
}) {
|
|
2529
|
-
return /* @__PURE__ */ jsx(
|
|
2530
|
-
Command$1.Separator,
|
|
2531
|
-
{
|
|
2532
|
-
className: cn("bg-border -mx-1 h-px", className),
|
|
2533
|
-
...props
|
|
2534
|
-
}
|
|
2535
|
-
);
|
|
2536
|
-
}
|
|
2537
|
-
function CommandItem({
|
|
2538
|
-
className,
|
|
2539
|
-
...props
|
|
2540
|
-
}) {
|
|
2541
|
-
return /* @__PURE__ */ jsx(
|
|
2542
|
-
Command$1.Item,
|
|
2543
|
-
{
|
|
2544
|
-
className: cn(
|
|
2545
|
-
"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
2546
|
-
className
|
|
2547
|
-
),
|
|
2548
|
-
...props
|
|
2549
|
-
}
|
|
2550
|
-
);
|
|
2551
|
-
}
|
|
2552
|
-
function CommandShortcut({
|
|
2553
|
-
className,
|
|
2554
|
-
...props
|
|
2555
|
-
}) {
|
|
2556
|
-
return /* @__PURE__ */ jsx(
|
|
2557
|
-
"span",
|
|
2558
|
-
{
|
|
2559
|
-
className: cn(
|
|
2560
|
-
"text-muted-foreground ml-auto text-xs tracking-widest",
|
|
2561
|
-
className
|
|
2562
|
-
),
|
|
2563
|
-
...props
|
|
2564
|
-
}
|
|
2565
|
-
);
|
|
2566
|
-
}
|
|
2567
|
-
function Combobox({
|
|
2568
|
-
options,
|
|
2569
|
-
value,
|
|
2570
|
-
onValueChange,
|
|
2571
|
-
placeholder = "Select...",
|
|
2572
|
-
mutedPlaceholder = true,
|
|
2573
|
-
searchPlaceholder = "Search...",
|
|
2574
|
-
emptyText = "No results found.",
|
|
2575
|
-
disabled = false,
|
|
2576
|
-
allowCreate = false,
|
|
2577
|
-
createLabel = "Create new",
|
|
2578
|
-
onCreateNew,
|
|
2579
|
-
loading = false,
|
|
2580
|
-
className,
|
|
2581
|
-
size = "default",
|
|
2582
|
-
align = "start",
|
|
2583
|
-
error = false,
|
|
2584
|
-
icon,
|
|
2585
|
-
"aria-label": ariaLabel
|
|
838
|
+
size = "default",
|
|
839
|
+
align = "start",
|
|
840
|
+
error = false,
|
|
841
|
+
icon,
|
|
842
|
+
"aria-label": ariaLabel
|
|
2586
843
|
}) {
|
|
2587
844
|
const [open, setOpen] = useState(false);
|
|
2588
845
|
const [searchValue, setSearchValue] = useState("");
|
|
@@ -2753,40 +1010,6 @@ function Combobox({
|
|
|
2753
1010
|
)
|
|
2754
1011
|
] });
|
|
2755
1012
|
}
|
|
2756
|
-
var Switch = React12.forwardRef(
|
|
2757
|
-
({ className, checked = false, onCheckedChange, disabled, ...props }, ref) => {
|
|
2758
|
-
return /* @__PURE__ */ jsx(
|
|
2759
|
-
"button",
|
|
2760
|
-
{
|
|
2761
|
-
type: "button",
|
|
2762
|
-
role: "switch",
|
|
2763
|
-
"aria-checked": checked,
|
|
2764
|
-
"data-state": checked ? "checked" : "unchecked",
|
|
2765
|
-
disabled,
|
|
2766
|
-
ref,
|
|
2767
|
-
onClick: () => onCheckedChange?.(!checked),
|
|
2768
|
-
className: cn(
|
|
2769
|
-
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors",
|
|
2770
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
2771
|
-
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
2772
|
-
checked ? "bg-primary" : "bg-input",
|
|
2773
|
-
className
|
|
2774
|
-
),
|
|
2775
|
-
...props,
|
|
2776
|
-
children: /* @__PURE__ */ jsx(
|
|
2777
|
-
"span",
|
|
2778
|
-
{
|
|
2779
|
-
className: cn(
|
|
2780
|
-
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform",
|
|
2781
|
-
checked ? "translate-x-4" : "translate-x-0"
|
|
2782
|
-
)
|
|
2783
|
-
}
|
|
2784
|
-
)
|
|
2785
|
-
}
|
|
2786
|
-
);
|
|
2787
|
-
}
|
|
2788
|
-
);
|
|
2789
|
-
Switch.displayName = "Switch";
|
|
2790
1013
|
function MobilePeriodStepper({
|
|
2791
1014
|
periodLabel,
|
|
2792
1015
|
onPrev,
|
|
@@ -3052,11 +1275,11 @@ function PeriodSelector({
|
|
|
3052
1275
|
className
|
|
3053
1276
|
}) {
|
|
3054
1277
|
const fiscalMonth = normalizeFiscalYearEndMonth(fiscalYearEndMonth);
|
|
3055
|
-
const now =
|
|
1278
|
+
const now = React5.useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
3056
1279
|
const selectedStart = safeParseDate(periodStart, now);
|
|
3057
1280
|
const selectedEnd = safeParseDate(periodEnd, now);
|
|
3058
1281
|
const anchorDate = granularity === "custom" ? selectedEnd : selectedStart;
|
|
3059
|
-
const ranges =
|
|
1282
|
+
const ranges = React5.useMemo(() => {
|
|
3060
1283
|
const map = /* @__PURE__ */ new Map();
|
|
3061
1284
|
for (const row of GRANULARITY_ROWS) {
|
|
3062
1285
|
const rowAnchor = row.key === granularity ? anchorDate : now;
|
|
@@ -3068,7 +1291,7 @@ function PeriodSelector({
|
|
|
3068
1291
|
return map;
|
|
3069
1292
|
}, [anchorDate, fiscalMonth, granularity, now]);
|
|
3070
1293
|
const activeLabel = allDates ? "All dates" : formatRangeLabel(granularity, selectedStart, selectedEnd);
|
|
3071
|
-
const applyRange =
|
|
1294
|
+
const applyRange = React5.useCallback(
|
|
3072
1295
|
(nextGranularity, nextRange) => {
|
|
3073
1296
|
onChange({
|
|
3074
1297
|
granularity: nextGranularity,
|
|
@@ -3080,7 +1303,7 @@ function PeriodSelector({
|
|
|
3080
1303
|
},
|
|
3081
1304
|
[onChange]
|
|
3082
1305
|
);
|
|
3083
|
-
const applyAllDates =
|
|
1306
|
+
const applyAllDates = React5.useCallback(() => {
|
|
3084
1307
|
onChange({
|
|
3085
1308
|
granularity,
|
|
3086
1309
|
periodStart: "",
|
|
@@ -3089,7 +1312,7 @@ function PeriodSelector({
|
|
|
3089
1312
|
allDates: true
|
|
3090
1313
|
});
|
|
3091
1314
|
}, [granularity, onChange]);
|
|
3092
|
-
const selectGranularity =
|
|
1315
|
+
const selectGranularity = React5.useCallback(
|
|
3093
1316
|
(nextGranularity) => {
|
|
3094
1317
|
const range = ranges.get(nextGranularity);
|
|
3095
1318
|
if (!range) return;
|
|
@@ -3097,7 +1320,7 @@ function PeriodSelector({
|
|
|
3097
1320
|
},
|
|
3098
1321
|
[applyRange, ranges]
|
|
3099
1322
|
);
|
|
3100
|
-
const navigate =
|
|
1323
|
+
const navigate = React5.useCallback(
|
|
3101
1324
|
(rowGranularity, direction) => {
|
|
3102
1325
|
const current = !allDates && granularity === rowGranularity ? { start: selectedStart, end: selectedEnd } : ranges.get(rowGranularity);
|
|
3103
1326
|
if (!current) return;
|
|
@@ -3918,7 +2141,7 @@ function PieChartView({
|
|
|
3918
2141
|
fill: card.color
|
|
3919
2142
|
}));
|
|
3920
2143
|
const pieTotal = pieData.reduce((sum, item) => sum + item.value, 0);
|
|
3921
|
-
const activeSliceKeys =
|
|
2144
|
+
const activeSliceKeys = React5.useMemo(() => {
|
|
3922
2145
|
if (!activeMetric) return /* @__PURE__ */ new Set();
|
|
3923
2146
|
const computed = computedMetrics?.find((m) => m.key === activeMetric);
|
|
3924
2147
|
if (computed) {
|
|
@@ -3926,7 +2149,7 @@ function PieChartView({
|
|
|
3926
2149
|
}
|
|
3927
2150
|
return /* @__PURE__ */ new Set([activeMetric]);
|
|
3928
2151
|
}, [activeMetric, computedMetrics]);
|
|
3929
|
-
const renderSlice =
|
|
2152
|
+
const renderSlice = React5.useCallback(
|
|
3930
2153
|
(props) => {
|
|
3931
2154
|
const {
|
|
3932
2155
|
cx,
|
|
@@ -4126,38 +2349,38 @@ function FinancialSummaryChart({
|
|
|
4126
2349
|
periodLabel: periodLabelProp,
|
|
4127
2350
|
className
|
|
4128
2351
|
}) {
|
|
4129
|
-
const [expanded, setExpanded] =
|
|
2352
|
+
const [expanded, setExpanded] = React5.useState(
|
|
4130
2353
|
() => resolveDefaultExpanded(config.defaultExpanded)
|
|
4131
2354
|
);
|
|
4132
|
-
const [activeChartType, setActiveChartType] =
|
|
2355
|
+
const [activeChartType, setActiveChartType] = React5.useState(
|
|
4133
2356
|
config.chartType ?? "area"
|
|
4134
2357
|
);
|
|
4135
|
-
const [activeMetric, setActiveMetric] =
|
|
4136
|
-
const [flippedCards, setFlippedCards] =
|
|
2358
|
+
const [activeMetric, setActiveMetric] = React5.useState(null);
|
|
2359
|
+
const [flippedCards, setFlippedCards] = React5.useState(
|
|
4137
2360
|
/* @__PURE__ */ new Set()
|
|
4138
2361
|
);
|
|
4139
|
-
const [mobileCardIndex, setMobileCardIndex] =
|
|
4140
|
-
const [useSwipeCards, setUseSwipeCards] =
|
|
4141
|
-
const touchStartRef =
|
|
4142
|
-
const touchDeltaRef =
|
|
2362
|
+
const [mobileCardIndex, setMobileCardIndex] = React5.useState(0);
|
|
2363
|
+
const [useSwipeCards, setUseSwipeCards] = React5.useState(false);
|
|
2364
|
+
const touchStartRef = React5.useRef(null);
|
|
2365
|
+
const touchDeltaRef = React5.useRef({ x: 0, y: 0 });
|
|
4143
2366
|
const divisor = config.chartDisplayUnits && config.chartDisplayUnits !== "auto" ? getUnitDivisor(config.chartDisplayUnits) : 1;
|
|
4144
|
-
const { chartData, summaryCards } =
|
|
2367
|
+
const { chartData, summaryCards } = React5.useMemo(
|
|
4145
2368
|
() => buildChartData(data, config, timeUnit, priorTotalsProp),
|
|
4146
2369
|
[data, config, timeUnit, priorTotalsProp]
|
|
4147
2370
|
);
|
|
4148
|
-
const visibleSummaryCards =
|
|
2371
|
+
const visibleSummaryCards = React5.useMemo(() => {
|
|
4149
2372
|
if (!config.statCardKeys?.length) return summaryCards;
|
|
4150
2373
|
const cardByKey = new Map(summaryCards.map((card) => [card.key, card]));
|
|
4151
2374
|
return config.statCardKeys.map((key) => cardByKey.get(key)).filter((card) => Boolean(card));
|
|
4152
2375
|
}, [config.statCardKeys, summaryCards]);
|
|
4153
2376
|
const cardFlipEnabled = config.enableCardFlip ?? true;
|
|
4154
|
-
|
|
2377
|
+
React5.useEffect(() => {
|
|
4155
2378
|
setExpanded(resolveDefaultExpanded(config.defaultExpanded));
|
|
4156
2379
|
}, [config.defaultExpanded]);
|
|
4157
|
-
|
|
2380
|
+
React5.useEffect(() => {
|
|
4158
2381
|
setActiveChartType(config.chartType ?? "area");
|
|
4159
2382
|
}, [config.chartType]);
|
|
4160
|
-
const allMetrics =
|
|
2383
|
+
const allMetrics = React5.useMemo(() => {
|
|
4161
2384
|
const baseChartType = config.chartType && config.chartType !== "pie" ? config.chartType : "area";
|
|
4162
2385
|
return [
|
|
4163
2386
|
...config.metrics.map((m) => ({
|
|
@@ -4178,7 +2401,7 @@ function FinancialSummaryChart({
|
|
|
4178
2401
|
}))
|
|
4179
2402
|
];
|
|
4180
2403
|
}, [config]);
|
|
4181
|
-
const axisValueDisplay =
|
|
2404
|
+
const axisValueDisplay = React5.useMemo(() => {
|
|
4182
2405
|
if (allMetrics.length === 0) return { format: "currency" };
|
|
4183
2406
|
const first = allMetrics[0]?.valueDisplay ?? { format: "currency" };
|
|
4184
2407
|
const firstFormat = first.format ?? "currency";
|
|
@@ -4189,12 +2412,12 @@ function FinancialSummaryChart({
|
|
|
4189
2412
|
});
|
|
4190
2413
|
return sameBase ? first : { format: "currency" };
|
|
4191
2414
|
}, [allMetrics]);
|
|
4192
|
-
|
|
2415
|
+
React5.useEffect(() => {
|
|
4193
2416
|
setMobileCardIndex(
|
|
4194
2417
|
(prev) => Math.min(Math.max(prev, 0), Math.max(visibleSummaryCards.length - 1, 0))
|
|
4195
2418
|
);
|
|
4196
2419
|
}, [visibleSummaryCards.length]);
|
|
4197
|
-
|
|
2420
|
+
React5.useEffect(() => {
|
|
4198
2421
|
if (typeof window === "undefined") return;
|
|
4199
2422
|
const coarsePointerQuery = window.matchMedia(
|
|
4200
2423
|
"(hover: none) and (pointer: coarse)"
|
|
@@ -4213,10 +2436,10 @@ function FinancialSummaryChart({
|
|
|
4213
2436
|
desktopWidthQuery.removeEventListener("change", syncSwipeMode);
|
|
4214
2437
|
};
|
|
4215
2438
|
}, []);
|
|
4216
|
-
const handleCardClick =
|
|
2439
|
+
const handleCardClick = React5.useCallback((key) => {
|
|
4217
2440
|
setActiveMetric((prev) => prev === key ? null : key);
|
|
4218
2441
|
}, []);
|
|
4219
|
-
const handleFlip =
|
|
2442
|
+
const handleFlip = React5.useCallback(
|
|
4220
2443
|
(e, key) => {
|
|
4221
2444
|
e.stopPropagation();
|
|
4222
2445
|
setFlippedCards((prev) => {
|
|
@@ -4228,7 +2451,7 @@ function FinancialSummaryChart({
|
|
|
4228
2451
|
},
|
|
4229
2452
|
[]
|
|
4230
2453
|
);
|
|
4231
|
-
const goToMobileCard =
|
|
2454
|
+
const goToMobileCard = React5.useCallback(
|
|
4232
2455
|
(nextIndex) => {
|
|
4233
2456
|
setMobileCardIndex(
|
|
4234
2457
|
Math.min(
|
|
@@ -4239,7 +2462,7 @@ function FinancialSummaryChart({
|
|
|
4239
2462
|
},
|
|
4240
2463
|
[visibleSummaryCards.length]
|
|
4241
2464
|
);
|
|
4242
|
-
const handleTouchStart =
|
|
2465
|
+
const handleTouchStart = React5.useCallback(
|
|
4243
2466
|
(e) => {
|
|
4244
2467
|
if (visibleSummaryCards.length <= 1) return;
|
|
4245
2468
|
const touch = e.touches[0];
|
|
@@ -4248,7 +2471,7 @@ function FinancialSummaryChart({
|
|
|
4248
2471
|
},
|
|
4249
2472
|
[visibleSummaryCards.length]
|
|
4250
2473
|
);
|
|
4251
|
-
const handleTouchMove =
|
|
2474
|
+
const handleTouchMove = React5.useCallback(
|
|
4252
2475
|
(e) => {
|
|
4253
2476
|
if (!touchStartRef.current || visibleSummaryCards.length <= 1) return;
|
|
4254
2477
|
const touch = e.touches[0];
|
|
@@ -4259,7 +2482,7 @@ function FinancialSummaryChart({
|
|
|
4259
2482
|
},
|
|
4260
2483
|
[visibleSummaryCards.length]
|
|
4261
2484
|
);
|
|
4262
|
-
const handleTouchEnd =
|
|
2485
|
+
const handleTouchEnd = React5.useCallback(() => {
|
|
4263
2486
|
if (!touchStartRef.current || visibleSummaryCards.length <= 1) return;
|
|
4264
2487
|
const { x, y } = touchDeltaRef.current;
|
|
4265
2488
|
const swipeThreshold = 40;
|
|
@@ -4270,7 +2493,7 @@ function FinancialSummaryChart({
|
|
|
4270
2493
|
touchStartRef.current = null;
|
|
4271
2494
|
touchDeltaRef.current = { x: 0, y: 0 };
|
|
4272
2495
|
}, [goToMobileCard, mobileCardIndex, visibleSummaryCards.length]);
|
|
4273
|
-
const getMetricOpacity =
|
|
2496
|
+
const getMetricOpacity = React5.useCallback(
|
|
4274
2497
|
(key) => {
|
|
4275
2498
|
if (!activeMetric) return 1;
|
|
4276
2499
|
if (key === activeMetric) return 1;
|
|
@@ -4286,7 +2509,7 @@ function FinancialSummaryChart({
|
|
|
4286
2509
|
[activeMetric, config.computedMetrics]
|
|
4287
2510
|
);
|
|
4288
2511
|
const hasChartToggle = !!config.chartTypes && config.chartTypes.length > 1;
|
|
4289
|
-
const renderSummaryCard =
|
|
2512
|
+
const renderSummaryCard = React5.useCallback(
|
|
4290
2513
|
(card) => {
|
|
4291
2514
|
const cardValueDisplay = card.valueDisplay ?? axisValueDisplay;
|
|
4292
2515
|
const isPositiveTrend = card.key === "expenses" ? (card.trend ?? 0) < 0 : (card.trend ?? 0) > 0;
|
|
@@ -5184,8 +3407,8 @@ function SummaryPanel({
|
|
|
5184
3407
|
renderChart,
|
|
5185
3408
|
chartControls
|
|
5186
3409
|
}) {
|
|
5187
|
-
const [expanded, setExpanded] =
|
|
5188
|
-
const [activeChartType, setActiveChartType] =
|
|
3410
|
+
const [expanded, setExpanded] = React5.useState(defaultExpanded);
|
|
3411
|
+
const [activeChartType, setActiveChartType] = React5.useState(defaultChartType);
|
|
5189
3412
|
const formatFn = formatValue ?? defaultFormat;
|
|
5190
3413
|
const hasChart = !!chartData && chartData.length > 0 && !!chartSeries || !!renderChart;
|
|
5191
3414
|
const hasChartToggle = chartTypes && chartTypes.length > 1;
|
|
@@ -5357,7 +3580,7 @@ function SummaryPanel({
|
|
|
5357
3580
|
] });
|
|
5358
3581
|
}
|
|
5359
3582
|
|
|
5360
|
-
// src/blocks/
|
|
3583
|
+
// src/blocks/finance/UnifiedTableControls.schema.ts
|
|
5361
3584
|
var unifiedTableControlOrder = [
|
|
5362
3585
|
"period",
|
|
5363
3586
|
"comparison",
|
|
@@ -5402,11 +3625,11 @@ function useUnifiedTableSettings(tableId, settings) {
|
|
|
5402
3625
|
);
|
|
5403
3626
|
}
|
|
5404
3627
|
function useIsMobile(breakpoint = 768) {
|
|
5405
|
-
const [isMobile, setIsMobile] =
|
|
3628
|
+
const [isMobile, setIsMobile] = React5.useState(() => {
|
|
5406
3629
|
if (typeof window === "undefined") return false;
|
|
5407
3630
|
return window.innerWidth < breakpoint;
|
|
5408
3631
|
});
|
|
5409
|
-
|
|
3632
|
+
React5.useEffect(() => {
|
|
5410
3633
|
const onResize = () => setIsMobile(window.innerWidth < breakpoint);
|
|
5411
3634
|
onResize();
|
|
5412
3635
|
window.addEventListener("resize", onResize);
|
|
@@ -5420,12 +3643,12 @@ function UnifiedTableControls({
|
|
|
5420
3643
|
className,
|
|
5421
3644
|
...props
|
|
5422
3645
|
}) {
|
|
5423
|
-
const normalized =
|
|
3646
|
+
const normalized = React5.useMemo(
|
|
5424
3647
|
() => normalizeUnifiedTableControls(controls),
|
|
5425
3648
|
[controls]
|
|
5426
3649
|
);
|
|
5427
3650
|
const isMobile = useIsMobile();
|
|
5428
|
-
const [mobileOpen, setMobileOpen] =
|
|
3651
|
+
const [mobileOpen, setMobileOpen] = React5.useState(false);
|
|
5429
3652
|
if (!normalized.length) return null;
|
|
5430
3653
|
if (!isMobile) {
|
|
5431
3654
|
return /* @__PURE__ */ jsx(
|
|
@@ -5534,4 +3757,4 @@ function UnifiedTableControls({
|
|
|
5534
3757
|
] });
|
|
5535
3758
|
}
|
|
5536
3759
|
|
|
5537
|
-
export { AreaLineChart, CASH_FLOW_CHART_CONFIG,
|
|
3760
|
+
export { AreaLineChart, CASH_FLOW_CHART_CONFIG, ChartTooltipRow, ChartTooltipShell, ChartTooltipTitle, ColumnChart, Combobox, ComparisonSelector, DataTableSettings, DatePicker, DateRangePicker, FinancialStatementControls, FinancialSummaryChart, INCOME_STATEMENT_CHART_CONFIG, MobilePeriodStepper, MobileStatementActions, MobileStatementFilters, ModernCalendar, PeriodSelector, PieChartView2 as PieChartView, SummaryPanel, Switch, UnifiedTableControls, createFinanceTableSettingsItems, normalizeUnifiedTableControls, unifiedTableControlOrder, useDataTableSettings, useUnifiedTableSettings };
|