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