@caffeinebounce/ui 0.62.2 → 0.63.0

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