@caffeinebounce/ui 0.62.2

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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/dist/FinancialStatementTable-BNUrdTU4.d.cts +249 -0
  4. package/dist/FinancialStatementTable-BNUrdTU4.d.ts +249 -0
  5. package/dist/NewsletterSignup-BPreFi5W.d.cts +37 -0
  6. package/dist/NewsletterSignup-BPreFi5W.d.ts +37 -0
  7. package/dist/TestimonialsSection-DtPu2OeR.d.ts +736 -0
  8. package/dist/TestimonialsSection-z-yotRfv.d.cts +736 -0
  9. package/dist/UnifiedTableControls-CG299y9h.d.ts +1233 -0
  10. package/dist/UnifiedTableControls-CIjRpNhy.d.cts +1233 -0
  11. package/dist/blog.d.cts +99 -0
  12. package/dist/blog.d.ts +99 -0
  13. package/dist/blog.js +292 -0
  14. package/dist/blog.mjs +279 -0
  15. package/dist/button-BHnoRUkF.d.cts +34 -0
  16. package/dist/button-BHnoRUkF.d.ts +34 -0
  17. package/dist/charts.d.cts +80 -0
  18. package/dist/charts.d.ts +80 -0
  19. package/dist/charts.js +19 -0
  20. package/dist/charts.mjs +2 -0
  21. package/dist/chunk-33JR5SYE.js +44 -0
  22. package/dist/chunk-3NDB4YPC.js +247 -0
  23. package/dist/chunk-5RW4PYZ6.js +1504 -0
  24. package/dist/chunk-5THF4YP6.mjs +155 -0
  25. package/dist/chunk-6BUBNZPG.mjs +164 -0
  26. package/dist/chunk-6DVWMJ3H.mjs +7029 -0
  27. package/dist/chunk-6TGV2DNP.js +120 -0
  28. package/dist/chunk-72JGQ7IJ.mjs +1498 -0
  29. package/dist/chunk-7DHKQODW.mjs +2932 -0
  30. package/dist/chunk-7IKHZKAC.js +160 -0
  31. package/dist/chunk-ADIDI7AJ.js +11 -0
  32. package/dist/chunk-BFWX5GJZ.mjs +940 -0
  33. package/dist/chunk-BMFQG6RA.mjs +5537 -0
  34. package/dist/chunk-C4UT5V3P.js +65 -0
  35. package/dist/chunk-CC4KUIKC.js +2004 -0
  36. package/dist/chunk-D3QXPL47.mjs +1814 -0
  37. package/dist/chunk-DQWHYBV2.js +36 -0
  38. package/dist/chunk-E42B4GSB.js +993 -0
  39. package/dist/chunk-ESZ7CBA2.js +1007 -0
  40. package/dist/chunk-EYJJQVV4.js +111 -0
  41. package/dist/chunk-FRRS2YZH.mjs +129 -0
  42. package/dist/chunk-G5TQWWQA.mjs +37 -0
  43. package/dist/chunk-GAIQJCAZ.js +5612 -0
  44. package/dist/chunk-GMBGWOCR.mjs +48 -0
  45. package/dist/chunk-GUSTCU2W.mjs +105 -0
  46. package/dist/chunk-HBLKVQIQ.mjs +23 -0
  47. package/dist/chunk-HMAMMC72.js +26 -0
  48. package/dist/chunk-IMKLN273.mjs +9 -0
  49. package/dist/chunk-J6OLBSZR.js +250 -0
  50. package/dist/chunk-JAE45W2T.js +28 -0
  51. package/dist/chunk-JORVSG52.js +606 -0
  52. package/dist/chunk-KB7UXIQZ.mjs +984 -0
  53. package/dist/chunk-KGGQ5NZV.js +186 -0
  54. package/dist/chunk-KHCC5UKW.mjs +22 -0
  55. package/dist/chunk-KRRIRS6A.mjs +1945 -0
  56. package/dist/chunk-LQCVRWVF.js +48 -0
  57. package/dist/chunk-MHZXUOGN.mjs +168 -0
  58. package/dist/chunk-MPZFPU4X.js +349 -0
  59. package/dist/chunk-MVYRNJA6.js +74 -0
  60. package/dist/chunk-N6AFNFZR.mjs +565 -0
  61. package/dist/chunk-OFQLWSUR.mjs +214 -0
  62. package/dist/chunk-OLAAXLXY.mjs +219 -0
  63. package/dist/chunk-OZZWDIOY.js +1859 -0
  64. package/dist/chunk-PZRI43EZ.js +111 -0
  65. package/dist/chunk-Q256HRYD.js +176 -0
  66. package/dist/chunk-Q52ZEL62.mjs +223 -0
  67. package/dist/chunk-R26Y7LGJ.js +142 -0
  68. package/dist/chunk-RBUYW6QQ.js +39 -0
  69. package/dist/chunk-RVEFPVZF.mjs +43 -0
  70. package/dist/chunk-SORWLKOK.js +96 -0
  71. package/dist/chunk-STEP6C4C.mjs +33 -0
  72. package/dist/chunk-T5R6HUDG.mjs +22 -0
  73. package/dist/chunk-T6ZBA6VJ.js +7109 -0
  74. package/dist/chunk-UM7WMXIU.js +2995 -0
  75. package/dist/chunk-VBD4Q5LL.mjs +117 -0
  76. package/dist/chunk-WOITB4JL.js +195 -0
  77. package/dist/chunk-YKZEKJMZ.mjs +71 -0
  78. package/dist/chunk-YL7RZRHM.mjs +103 -0
  79. package/dist/chunk-YSLD2HLP.mjs +346 -0
  80. package/dist/chunk-ZFLZA7UP.mjs +140 -0
  81. package/dist/chunk-ZKUIUE7W.mjs +26 -0
  82. package/dist/chunk-ZOA7B32D.js +248 -0
  83. package/dist/data-table.d.cts +46 -0
  84. package/dist/data-table.d.ts +46 -0
  85. package/dist/data-table.js +270 -0
  86. package/dist/data-table.mjs +13 -0
  87. package/dist/editor.d.cts +89 -0
  88. package/dist/editor.d.ts +89 -0
  89. package/dist/editor.js +10 -0
  90. package/dist/editor.mjs +1 -0
  91. package/dist/forms.d.cts +142 -0
  92. package/dist/forms.d.ts +142 -0
  93. package/dist/forms.js +24 -0
  94. package/dist/forms.mjs +11 -0
  95. package/dist/hooks-8ORd7T1A.d.cts +751 -0
  96. package/dist/hooks-B2jU1GVT.d.ts +751 -0
  97. package/dist/hooks.d.cts +6 -0
  98. package/dist/hooks.d.ts +6 -0
  99. package/dist/hooks.js +99 -0
  100. package/dist/hooks.mjs +10 -0
  101. package/dist/index.d.cts +3141 -0
  102. package/dist/index.d.ts +3141 -0
  103. package/dist/index.js +7332 -0
  104. package/dist/index.mjs +5876 -0
  105. package/dist/layouts-DPfDDF53.d.cts +1001 -0
  106. package/dist/layouts-DPfDDF53.d.ts +1001 -0
  107. package/dist/layouts.d.cts +4 -0
  108. package/dist/layouts.d.ts +4 -0
  109. package/dist/layouts.js +100 -0
  110. package/dist/layouts.mjs +11 -0
  111. package/dist/marketing-3d.d.cts +51 -0
  112. package/dist/marketing-3d.d.ts +51 -0
  113. package/dist/marketing-3d.js +553 -0
  114. package/dist/marketing-3d.mjs +526 -0
  115. package/dist/marketing.d.cts +583 -0
  116. package/dist/marketing.d.ts +583 -0
  117. package/dist/marketing.js +299 -0
  118. package/dist/marketing.mjs +10 -0
  119. package/dist/media.d.cts +29 -0
  120. package/dist/media.d.ts +29 -0
  121. package/dist/media.js +189 -0
  122. package/dist/media.mjs +182 -0
  123. package/dist/navigation.d.cts +591 -0
  124. package/dist/navigation.d.ts +591 -0
  125. package/dist/navigation.js +108 -0
  126. package/dist/navigation.mjs +15 -0
  127. package/dist/portal.d.cts +58 -0
  128. package/dist/portal.d.ts +58 -0
  129. package/dist/portal.js +403 -0
  130. package/dist/portal.mjs +395 -0
  131. package/dist/primitives.d.cts +508 -0
  132. package/dist/primitives.d.ts +508 -0
  133. package/dist/primitives.js +295 -0
  134. package/dist/primitives.mjs +14 -0
  135. package/dist/settings.d.cts +216 -0
  136. package/dist/settings.d.ts +216 -0
  137. package/dist/settings.js +34 -0
  138. package/dist/settings.mjs +9 -0
  139. package/dist/shared-Dqn36QHZ.d.cts +4 -0
  140. package/dist/shared-Dqn36QHZ.d.ts +4 -0
  141. package/dist/styles.css +1213 -0
  142. package/package.json +189 -0
  143. package/styles.css +1 -0
@@ -0,0 +1,2995 @@
1
+ 'use strict';
2
+
3
+ var chunkWOITB4JL_js = require('./chunk-WOITB4JL.js');
4
+ var chunk6TGV2DNP_js = require('./chunk-6TGV2DNP.js');
5
+ var chunkJ6OLBSZR_js = require('./chunk-J6OLBSZR.js');
6
+ var chunkSORWLKOK_js = require('./chunk-SORWLKOK.js');
7
+ var chunkDQWHYBV2_js = require('./chunk-DQWHYBV2.js');
8
+ var chunkADIDI7AJ_js = require('./chunk-ADIDI7AJ.js');
9
+ var PopoverPrimitive = require('@radix-ui/react-popover');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+ var lucideReact = require('lucide-react');
12
+ var React3 = require('react');
13
+ var reactTable = require('@tanstack/react-table');
14
+
15
+ function _interopNamespace(e) {
16
+ if (e && e.__esModule) return e;
17
+ var n = Object.create(null);
18
+ if (e) {
19
+ Object.keys(e).forEach(function (k) {
20
+ if (k !== 'default') {
21
+ var d = Object.getOwnPropertyDescriptor(e, k);
22
+ Object.defineProperty(n, k, d.get ? d : {
23
+ enumerable: true,
24
+ get: function () { return e[k]; }
25
+ });
26
+ }
27
+ });
28
+ }
29
+ n.default = e;
30
+ return Object.freeze(n);
31
+ }
32
+
33
+ var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
34
+ var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
35
+
36
+ var Popover = PopoverPrimitive__namespace.Root;
37
+ var PopoverTrigger = PopoverPrimitive__namespace.Trigger;
38
+ var PopoverAnchor = PopoverPrimitive__namespace.Anchor;
39
+ function PopoverContent({
40
+ className,
41
+ align = "center",
42
+ sideOffset = 4,
43
+ ...props
44
+ }) {
45
+ return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
46
+ PopoverPrimitive__namespace.Content,
47
+ {
48
+ align,
49
+ sideOffset,
50
+ className: chunkADIDI7AJ_js.cn(
51
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-box border p-4 shadow-md outline-none",
52
+ className
53
+ ),
54
+ ...props
55
+ }
56
+ ) });
57
+ }
58
+ function Table({ className, ...props }) {
59
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
60
+ "table",
61
+ {
62
+ "data-slot": "table",
63
+ className: chunkADIDI7AJ_js.cn("w-full caption-bottom text-sm", className),
64
+ ...props
65
+ }
66
+ ) });
67
+ }
68
+ function TableHeader({ className, ...props }) {
69
+ return /* @__PURE__ */ jsxRuntime.jsx(
70
+ "thead",
71
+ {
72
+ "data-slot": "table-header",
73
+ className: chunkADIDI7AJ_js.cn("[&_tr]:border-b", className),
74
+ ...props
75
+ }
76
+ );
77
+ }
78
+ function TableBody({ className, ...props }) {
79
+ return /* @__PURE__ */ jsxRuntime.jsx(
80
+ "tbody",
81
+ {
82
+ "data-slot": "table-body",
83
+ className: chunkADIDI7AJ_js.cn("[&_tr:last-child]:border-0", className),
84
+ ...props
85
+ }
86
+ );
87
+ }
88
+ function TableFooter({ className, ...props }) {
89
+ return /* @__PURE__ */ jsxRuntime.jsx(
90
+ "tfoot",
91
+ {
92
+ "data-slot": "table-footer",
93
+ className: chunkADIDI7AJ_js.cn(
94
+ "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
95
+ className
96
+ ),
97
+ ...props
98
+ }
99
+ );
100
+ }
101
+ function TableRow({ className, ...props }) {
102
+ return /* @__PURE__ */ jsxRuntime.jsx(
103
+ "tr",
104
+ {
105
+ "data-slot": "table-row",
106
+ className: chunkADIDI7AJ_js.cn(
107
+ "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
108
+ className
109
+ ),
110
+ ...props
111
+ }
112
+ );
113
+ }
114
+ function TableHead({ className, ...props }) {
115
+ return /* @__PURE__ */ jsxRuntime.jsx(
116
+ "th",
117
+ {
118
+ "data-slot": "table-head",
119
+ className: chunkADIDI7AJ_js.cn(
120
+ "text-muted-foreground h-10 px-2 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
121
+ className
122
+ ),
123
+ ...props
124
+ }
125
+ );
126
+ }
127
+ function TableCell({ className, ...props }) {
128
+ return /* @__PURE__ */ jsxRuntime.jsx(
129
+ "td",
130
+ {
131
+ "data-slot": "table-cell",
132
+ className: chunkADIDI7AJ_js.cn(
133
+ "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
134
+ className
135
+ ),
136
+ ...props
137
+ }
138
+ );
139
+ }
140
+ function TableCaption({
141
+ className,
142
+ ...props
143
+ }) {
144
+ return /* @__PURE__ */ jsxRuntime.jsx(
145
+ "caption",
146
+ {
147
+ "data-slot": "table-caption",
148
+ className: chunkADIDI7AJ_js.cn("text-muted-foreground mt-4 text-sm", className),
149
+ ...props
150
+ }
151
+ );
152
+ }
153
+ var colorMap = {
154
+ green: "#22c55e",
155
+ red: "#ef4444",
156
+ blue: "#3b82f6",
157
+ yellow: "#eab308",
158
+ orange: "#f97316",
159
+ purple: "#a855f7",
160
+ pink: "#ec4899",
161
+ gray: "#6b7280",
162
+ slate: "#64748b"
163
+ };
164
+ function getColorValue(color) {
165
+ if (!color) return void 0;
166
+ return colorMap[color.toLowerCase()] ?? color;
167
+ }
168
+ function TextLikeFilterBody({
169
+ type,
170
+ placeholder,
171
+ value,
172
+ onValueChange,
173
+ onApply,
174
+ onClear
175
+ }) {
176
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-2 py-2", children: [
177
+ /* @__PURE__ */ jsxRuntime.jsx(
178
+ chunkDQWHYBV2_js.Input,
179
+ {
180
+ type: type === "number" ? "number" : void 0,
181
+ placeholder,
182
+ value,
183
+ onChange: (e) => onValueChange(e.target.value),
184
+ onKeyDown: (e) => {
185
+ if (e.key === "Enter") {
186
+ e.preventDefault();
187
+ onApply();
188
+ }
189
+ },
190
+ className: "h-8 text-xs",
191
+ autoFocus: true
192
+ }
193
+ ),
194
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mt-2 gap-2", children: [
195
+ value && /* @__PURE__ */ jsxRuntime.jsx(
196
+ chunk6TGV2DNP_js.Button,
197
+ {
198
+ variant: "ghost",
199
+ size: "sm",
200
+ className: "h-7 text-xs px-2 text-muted-foreground hover:text-foreground",
201
+ onClick: onClear,
202
+ children: "Clear"
203
+ }
204
+ ),
205
+ /* @__PURE__ */ jsxRuntime.jsx(
206
+ chunk6TGV2DNP_js.Button,
207
+ {
208
+ size: "sm",
209
+ className: "h-7 text-xs px-3 ml-auto",
210
+ onClick: onApply,
211
+ children: "Apply"
212
+ }
213
+ )
214
+ ] })
215
+ ] });
216
+ }
217
+ function DataTableColumnFilterContent({
218
+ title,
219
+ value,
220
+ onChange,
221
+ onClear,
222
+ onDelete,
223
+ filterType = "text",
224
+ filterOptions,
225
+ placeholder,
226
+ showDeleteMenu = true
227
+ }) {
228
+ const [localValue, setLocalValue] = React3__namespace.useState(value ?? "");
229
+ const [operator, setOperator] = React3__namespace.useState("is");
230
+ React3__namespace.useEffect(() => setLocalValue(value ?? ""), [value]);
231
+ const handleApply = () => onChange(localValue || void 0);
232
+ const handleClear = () => {
233
+ setLocalValue("");
234
+ onClear?.();
235
+ onChange(void 0);
236
+ };
237
+ const selectedValues = React3__namespace.useMemo(() => {
238
+ if (!localValue) return /* @__PURE__ */ new Set();
239
+ return new Set(localValue.split(",").filter(Boolean));
240
+ }, [localValue]);
241
+ const toggleOption = (optionValue) => {
242
+ const newSelected = new Set(selectedValues);
243
+ if (newSelected.has(optionValue)) {
244
+ newSelected.delete(optionValue);
245
+ } else {
246
+ newSelected.add(optionValue);
247
+ }
248
+ const newValue = Array.from(newSelected).join(",");
249
+ setLocalValue(newValue);
250
+ onChange(newValue || void 0);
251
+ };
252
+ const hasValue = Boolean(localValue);
253
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-52", children: [
254
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-3 py-2 border-b border-border", children: [
255
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground", children: title }),
256
+ /* @__PURE__ */ jsxRuntime.jsxs(
257
+ chunkWOITB4JL_js.Select,
258
+ {
259
+ value: operator,
260
+ onValueChange: (v) => setOperator(v),
261
+ children: [
262
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWOITB4JL_js.SelectTrigger, { className: "!h-auto !min-h-0 !py-0.5 w-auto gap-1 border-0 shadow-none bg-muted/50 px-1.5 text-xs text-muted-foreground hover:text-foreground hover:bg-muted rounded focus:ring-0 focus:ring-offset-0 focus-visible:ring-0", children: /* @__PURE__ */ jsxRuntime.jsx(chunkWOITB4JL_js.SelectValue, {}) }),
263
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkWOITB4JL_js.SelectContent, { children: [
264
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWOITB4JL_js.SelectItem, { value: "is", className: "text-xs", children: "is" }),
265
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWOITB4JL_js.SelectItem, { value: "is_not", className: "text-xs", children: "is not" }),
266
+ filterType === "text" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
267
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWOITB4JL_js.SelectItem, { value: "contains", className: "text-xs", children: "contains" }),
268
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWOITB4JL_js.SelectItem, { value: "does_not_contain", className: "text-xs", children: "does not contain" })
269
+ ] }),
270
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWOITB4JL_js.SelectItem, { value: "is_empty", className: "text-xs", children: "is empty" }),
271
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWOITB4JL_js.SelectItem, { value: "is_not_empty", className: "text-xs", children: "is not empty" })
272
+ ] })
273
+ ]
274
+ }
275
+ ),
276
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
277
+ showDeleteMenu && hasValue && /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenu, { children: [
278
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(chunk6TGV2DNP_js.Button, { variant: "ghost-icon", size: "icon-sm", className: "size-5", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-3.5" }) }) }),
279
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuContent, { align: "start", side: "right", sideOffset: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(
280
+ chunkJ6OLBSZR_js.DropdownMenuItem,
281
+ {
282
+ onClick: onDelete ?? handleClear,
283
+ className: "text-xs gap-2",
284
+ children: [
285
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-3.5" }),
286
+ "Delete filter"
287
+ ]
288
+ }
289
+ ) })
290
+ ] })
291
+ ] }),
292
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-1", children: [
293
+ filterType === "text" && /* @__PURE__ */ jsxRuntime.jsx(
294
+ TextLikeFilterBody,
295
+ {
296
+ placeholder: placeholder ?? `Search ${title.toLowerCase()}...`,
297
+ value: localValue,
298
+ onValueChange: setLocalValue,
299
+ onApply: handleApply,
300
+ onClear: handleClear
301
+ }
302
+ ),
303
+ filterType === "number" && /* @__PURE__ */ jsxRuntime.jsx(
304
+ TextLikeFilterBody,
305
+ {
306
+ type: "number",
307
+ placeholder: placeholder ?? `Enter ${title.toLowerCase()}...`,
308
+ value: localValue,
309
+ onValueChange: setLocalValue,
310
+ onApply: handleApply,
311
+ onClear: handleClear
312
+ }
313
+ ),
314
+ filterType === "select" && filterOptions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-64 overflow-y-auto px-1", children: filterOptions.map((option) => {
315
+ const isSelected = selectedValues.has(option.value);
316
+ const colorValue = getColorValue(option.color);
317
+ return /* @__PURE__ */ jsxRuntime.jsxs(
318
+ "button",
319
+ {
320
+ type: "button",
321
+ className: chunkADIDI7AJ_js.cn(
322
+ "flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-xs transition-colors",
323
+ "hover:bg-muted",
324
+ isSelected && "bg-muted/50"
325
+ ),
326
+ onClick: () => toggleOption(option.value),
327
+ children: [
328
+ /* @__PURE__ */ jsxRuntime.jsx(
329
+ "div",
330
+ {
331
+ className: chunkADIDI7AJ_js.cn(
332
+ "flex size-3.5 shrink-0 items-center justify-center rounded-sm border self-center",
333
+ isSelected ? "border-primary bg-primary text-primary-foreground" : "border-muted-foreground/30"
334
+ ),
335
+ children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-2.5" })
336
+ }
337
+ ),
338
+ option.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 flex items-center", children: option.badge }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
339
+ (colorValue || option.icon) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: option.icon ? option.icon : /* @__PURE__ */ jsxRuntime.jsx(
340
+ "span",
341
+ {
342
+ className: "inline-block size-2 rounded-full",
343
+ style: { backgroundColor: colorValue }
344
+ }
345
+ ) }),
346
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: option.label })
347
+ ] })
348
+ ]
349
+ },
350
+ option.value
351
+ );
352
+ }) }),
353
+ filterType === "boolean" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1", children: (filterOptions ?? [
354
+ { label: "Yes", value: "true", color: "green" },
355
+ { label: "No", value: "false", color: "red" }
356
+ ]).map((opt) => {
357
+ const isSelected = selectedValues.has(opt.value);
358
+ const colorValue = opt.color ? getColorValue(opt.color) : void 0;
359
+ let iconElement = null;
360
+ if (opt.icon) {
361
+ if (React3__namespace.isValidElement(opt.icon)) {
362
+ iconElement = opt.icon;
363
+ } else {
364
+ const Icon = opt.icon;
365
+ iconElement = /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-3" });
366
+ }
367
+ }
368
+ return /* @__PURE__ */ jsxRuntime.jsxs(
369
+ "button",
370
+ {
371
+ type: "button",
372
+ className: chunkADIDI7AJ_js.cn(
373
+ "flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-xs transition-colors",
374
+ "hover:bg-muted",
375
+ isSelected && "bg-muted/50"
376
+ ),
377
+ onClick: () => toggleOption(opt.value),
378
+ children: [
379
+ /* @__PURE__ */ jsxRuntime.jsx(
380
+ "div",
381
+ {
382
+ className: chunkADIDI7AJ_js.cn(
383
+ "flex size-3.5 shrink-0 items-center justify-center rounded-sm border self-center",
384
+ isSelected ? "border-primary bg-primary text-primary-foreground" : "border-muted-foreground/30"
385
+ ),
386
+ children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-2.5" })
387
+ }
388
+ ),
389
+ opt.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center", children: opt.badge }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
390
+ colorValue && /* @__PURE__ */ jsxRuntime.jsx(
391
+ "span",
392
+ {
393
+ className: "inline-block size-2 rounded-full",
394
+ style: { backgroundColor: colorValue }
395
+ }
396
+ ),
397
+ iconElement && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground [&>svg]:size-3", children: iconElement }),
398
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: opt.label })
399
+ ] })
400
+ ]
401
+ },
402
+ opt.value
403
+ );
404
+ }) })
405
+ ] }),
406
+ (filterType === "select" || filterType === "boolean") && selectedValues.size > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border px-1 py-1", children: /* @__PURE__ */ jsxRuntime.jsx(
407
+ "button",
408
+ {
409
+ type: "button",
410
+ className: "flex w-full items-center rounded-md px-2 py-1.5 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
411
+ onClick: handleClear,
412
+ children: "Clear filter"
413
+ }
414
+ ) })
415
+ ] });
416
+ }
417
+ function DataTableColumnFilter({
418
+ column,
419
+ title,
420
+ filterType = "text",
421
+ filterOptions,
422
+ placeholder,
423
+ children,
424
+ onFilterChange
425
+ }) {
426
+ const [open, setOpen] = React3__namespace.useState(false);
427
+ const current = column.getFilterValue();
428
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
429
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children }),
430
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { align: "start", className: "w-56 p-0", sideOffset: 4, children: /* @__PURE__ */ jsxRuntime.jsx(
431
+ DataTableColumnFilterContent,
432
+ {
433
+ title,
434
+ value: current,
435
+ onChange: (v) => {
436
+ column.setFilterValue(v);
437
+ onFilterChange?.(column.id, v);
438
+ },
439
+ onClear: () => column.setFilterValue(void 0),
440
+ filterType,
441
+ filterOptions,
442
+ placeholder,
443
+ showDeleteMenu: false
444
+ }
445
+ ) })
446
+ ] });
447
+ }
448
+ function DataTableFilterBadges({
449
+ filters,
450
+ onRemoveFilter,
451
+ onChangeFilter,
452
+ onClearAll,
453
+ onAddFilter,
454
+ className,
455
+ ...props
456
+ }) {
457
+ if (filters.length === 0 && !onAddFilter) {
458
+ return null;
459
+ }
460
+ return /* @__PURE__ */ jsxRuntime.jsxs(
461
+ "div",
462
+ {
463
+ className: chunkADIDI7AJ_js.cn("flex flex-wrap items-center gap-1.5", className),
464
+ ...props,
465
+ children: [
466
+ filters.map((filter) => /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenu, { children: [
467
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
468
+ "button",
469
+ {
470
+ type: "button",
471
+ className: chunkADIDI7AJ_js.cn(
472
+ "inline-flex items-center gap-1 rounded border border-sky-200 dark:border-sky-800 bg-sky-50 dark:bg-sky-950/30 px-1.5 py-0.5",
473
+ "text-xs hover:bg-sky-100 dark:hover:bg-sky-900/40 transition-colors cursor-pointer"
474
+ ),
475
+ children: [
476
+ filter.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground shrink-0 [&>svg]:size-3", children: React3__namespace.isValidElement(filter.icon) ? filter.icon : (() => {
477
+ const Icon = filter.icon;
478
+ return /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-3" });
479
+ })() }),
480
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: filter.label }),
481
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50", children: "\xB7" }),
482
+ filter.valueBadge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center", children: filter.valueBadge }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium truncate max-w-28", children: filter.value }),
483
+ /* @__PURE__ */ jsxRuntime.jsx(
484
+ "button",
485
+ {
486
+ type: "button",
487
+ onPointerDown: (e) => {
488
+ e.stopPropagation();
489
+ e.preventDefault();
490
+ },
491
+ onClick: (e) => {
492
+ e.stopPropagation();
493
+ e.preventDefault();
494
+ onRemoveFilter(filter.id);
495
+ },
496
+ className: "ml-0.5 rounded-sm p-0.5 hover:bg-sky-200/50 dark:hover:bg-sky-800/50 -mr-0.5",
497
+ "aria-label": `Remove ${filter.label} filter`,
498
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3 text-muted-foreground" })
499
+ }
500
+ )
501
+ ]
502
+ }
503
+ ) }),
504
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuContent, { sideOffset: 4, align: "start", className: "p-0", children: /* @__PURE__ */ jsxRuntime.jsx(
505
+ DataTableColumnFilterContent,
506
+ {
507
+ title: filter.label,
508
+ value: filter.rawValue ?? filter.value,
509
+ onChange: (v) => onChangeFilter?.(filter.id, v),
510
+ onClear: () => onRemoveFilter(filter.id),
511
+ onDelete: () => onRemoveFilter(filter.id),
512
+ filterType: filter.filterType,
513
+ filterOptions: filter.filterOptions,
514
+ placeholder: filter.filterPlaceholder,
515
+ showDeleteMenu: true
516
+ }
517
+ ) })
518
+ ] }, filter.id)),
519
+ onAddFilter && /* @__PURE__ */ jsxRuntime.jsxs(
520
+ "button",
521
+ {
522
+ type: "button",
523
+ onClick: onAddFilter,
524
+ className: chunkADIDI7AJ_js.cn(
525
+ "inline-flex items-center gap-1 rounded px-1.5 py-0.5",
526
+ "text-xs text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors"
527
+ ),
528
+ children: [
529
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "size-3" }),
530
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Filter" })
531
+ ]
532
+ }
533
+ ),
534
+ onClearAll && filters.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
535
+ "button",
536
+ {
537
+ type: "button",
538
+ onClick: onClearAll,
539
+ className: "text-xs text-muted-foreground hover:text-foreground ml-0.5",
540
+ children: "Clear"
541
+ }
542
+ )
543
+ ]
544
+ }
545
+ );
546
+ }
547
+ var DataTableContext = React3__namespace.createContext(null);
548
+ function useDataTableContext() {
549
+ return React3__namespace.useContext(DataTableContext);
550
+ }
551
+ function TreeExpandCycleButton({
552
+ table,
553
+ density
554
+ }) {
555
+ const depthRef = React3__namespace.useRef(-1);
556
+ const maxDepth = React3__namespace.useMemo(() => {
557
+ let max = 0;
558
+ const walk = (rows) => {
559
+ for (const row of rows) {
560
+ if (row.depth > max) max = row.depth;
561
+ if (row.subRows?.length) walk(row.subRows);
562
+ }
563
+ };
564
+ walk(
565
+ table.getPreExpandedRowModel?.()?.rows ?? table.getCoreRowModel().rows
566
+ );
567
+ return max;
568
+ }, [table]);
569
+ const handleClick = React3__namespace.useCallback(() => {
570
+ const nextDepth = depthRef.current + 1;
571
+ if (nextDepth > maxDepth) {
572
+ table.toggleAllRowsExpanded(false);
573
+ depthRef.current = -1;
574
+ return;
575
+ }
576
+ const newExpanded = {};
577
+ const allRows = table.getPreExpandedRowModel?.()?.rows ?? table.getCoreRowModel().rows;
578
+ const walk = (rows) => {
579
+ for (const row of rows) {
580
+ if (row.depth <= nextDepth && row.getCanExpand()) {
581
+ newExpanded[row.id] = true;
582
+ }
583
+ if (row.subRows?.length) walk(row.subRows);
584
+ }
585
+ };
586
+ walk(allRows);
587
+ table.setExpanded(newExpanded);
588
+ depthRef.current = nextDepth;
589
+ }, [table, maxDepth]);
590
+ const isAllExpanded = table.getIsAllRowsExpanded();
591
+ const isSomeExpanded = table.getIsSomeRowsExpanded();
592
+ const iconSize = density === "compact" ? "size-3.5" : "size-4";
593
+ return /* @__PURE__ */ jsxRuntime.jsx(
594
+ "button",
595
+ {
596
+ type: "button",
597
+ onClick: handleClick,
598
+ className: chunkADIDI7AJ_js.cn(
599
+ "inline-flex items-center justify-center shrink-0 text-muted-foreground hover:text-foreground rounded hover:bg-accent transition-colors",
600
+ density === "compact" ? "size-5 ml-0.5" : "size-6 ml-1"
601
+ ),
602
+ "aria-label": isAllExpanded ? "Collapse all rows" : "Expand next level",
603
+ title: isAllExpanded ? "Collapse all" : isSomeExpanded ? "Expand next level" : "Expand all",
604
+ children: isAllExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownUp, { className: iconSize }) : isSomeExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: iconSize }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: iconSize })
605
+ }
606
+ );
607
+ }
608
+ function DataTable({
609
+ table,
610
+ columns,
611
+ actionBar,
612
+ floatingBar,
613
+ filters,
614
+ onRemoveFilter,
615
+ onChangeFilter,
616
+ onClearAllFilters,
617
+ onAddFilter,
618
+ density = "comfy",
619
+ fontSize = "sm",
620
+ enableColumnResizing = false,
621
+ rowSelectionStyle = "hover",
622
+ enableRowDrag = true,
623
+ onRowDragEnd,
624
+ enableColumnDrag = false,
625
+ columnOrder: externalColumnOrder,
626
+ onColumnOrderChange,
627
+ columnWrapping: externalColumnWrapping,
628
+ onColumnWrappingChange,
629
+ onRowClick,
630
+ summary,
631
+ enableTreeView = false,
632
+ treeIndentPx = 20,
633
+ getRowClassName: getRowClassName2,
634
+ stickyColumns = 0,
635
+ stickyColumnIds: explicitStickyColumnIds,
636
+ className,
637
+ children,
638
+ ...props
639
+ }) {
640
+ const cellPadding = density === "compact" ? "px-1.5 py-0.5" : "px-2 py-1";
641
+ const headerHeight = density === "compact" ? "h-7" : "h-8";
642
+ const fontSizeClass = {
643
+ xs: "text-[10px]",
644
+ sm: "text-xs",
645
+ md: "text-sm",
646
+ lg: "text-base"
647
+ }[fontSize];
648
+ const checkboxSize = {
649
+ xs: "size-3.5",
650
+ sm: "size-4",
651
+ md: "size-4.5",
652
+ lg: "size-5"
653
+ }[fontSize];
654
+ const checkmarkSize = {
655
+ xs: "size-2",
656
+ sm: "size-2.5",
657
+ md: "size-3",
658
+ lg: "size-3.5"
659
+ }[fontSize];
660
+ const [columnSizing, setColumnSizing] = React3__namespace.useState({});
661
+ const [resizingColumn, setResizingColumn] = React3__namespace.useState(
662
+ null
663
+ );
664
+ const [hoveredRowId, setHoveredRowId] = React3__namespace.useState(null);
665
+ const defaultColumnOrder = React3__namespace.useMemo(
666
+ () => columns.map(
667
+ (col) => col.id ? col.id : "accessorKey" in col ? String(col.accessorKey) : ""
668
+ ),
669
+ [columns]
670
+ );
671
+ const [internalColumnOrder, setInternalColumnOrder] = React3__namespace.useState(defaultColumnOrder);
672
+ const columnOrder = externalColumnOrder ?? internalColumnOrder;
673
+ const setColumnOrder = onColumnOrderChange ?? setInternalColumnOrder;
674
+ const renderedLeafColumns = React3__namespace.useMemo(() => {
675
+ let leafColumns = table.getVisibleLeafColumns();
676
+ if (rowSelectionStyle === "hover" || enableRowDrag) {
677
+ leafColumns = leafColumns.filter((column) => column.id !== "select");
678
+ }
679
+ if (enableColumnDrag) {
680
+ leafColumns = [...leafColumns].sort((a, b) => {
681
+ const aIndex = columnOrder.indexOf(a.id);
682
+ const bIndex = columnOrder.indexOf(b.id);
683
+ if (aIndex === -1) return 1;
684
+ if (bIndex === -1) return -1;
685
+ return aIndex - bIndex;
686
+ });
687
+ }
688
+ return leafColumns;
689
+ }, [table, rowSelectionStyle, enableRowDrag, enableColumnDrag, columnOrder]);
690
+ const renderedLeafIndexById = React3__namespace.useMemo(() => {
691
+ const indexById = /* @__PURE__ */ new Map();
692
+ renderedLeafColumns.forEach((column, index) => {
693
+ indexById.set(column.id, index);
694
+ });
695
+ return indexById;
696
+ }, [renderedLeafColumns]);
697
+ const stickyLeafColumns = React3__namespace.useMemo(() => {
698
+ if (explicitStickyColumnIds && explicitStickyColumnIds.length > 0) {
699
+ const stickyIdSet = new Set(explicitStickyColumnIds);
700
+ return renderedLeafColumns.filter((column) => stickyIdSet.has(column.id));
701
+ }
702
+ if (!stickyColumns || stickyColumns <= 0) return [];
703
+ return renderedLeafColumns.slice(0, stickyColumns);
704
+ }, [renderedLeafColumns, stickyColumns, explicitStickyColumnIds]);
705
+ const stickyColumnIds = React3__namespace.useMemo(
706
+ () => new Set(stickyLeafColumns.map((column) => column.id)),
707
+ [stickyLeafColumns]
708
+ );
709
+ const stickyColumnLefts = React3__namespace.useMemo(() => {
710
+ const lefts = /* @__PURE__ */ new Map();
711
+ let runningLeft = 0;
712
+ for (const column of stickyLeafColumns) {
713
+ lefts.set(column.id, runningLeft);
714
+ runningLeft += column.getSize();
715
+ }
716
+ return lefts;
717
+ }, [stickyLeafColumns]);
718
+ const renderedTableWidth = React3__namespace.useMemo(() => {
719
+ return renderedLeafColumns.reduce((total, column) => {
720
+ const resizedWidth = columnSizing[column.id];
721
+ const baseWidth = resizedWidth ?? column.getSize();
722
+ const minWidth = column.columnDef.minSize ?? 0;
723
+ const maxWidth = column.columnDef.maxSize;
724
+ const clamped = Math.max(
725
+ minWidth,
726
+ maxWidth !== void 0 ? Math.min(baseWidth, maxWidth) : baseWidth
727
+ );
728
+ return total + clamped;
729
+ }, 0);
730
+ }, [renderedLeafColumns, columnSizing]);
731
+ const [internalColumnWrapping, setInternalColumnWrapping] = React3__namespace.useState({});
732
+ const columnWrapping = externalColumnWrapping ?? internalColumnWrapping;
733
+ const setColumnWrapping = onColumnWrappingChange ?? setInternalColumnWrapping;
734
+ const [draggedColumnId, setDraggedColumnId] = React3__namespace.useState(
735
+ null
736
+ );
737
+ const [dragOverColumnId, setDragOverColumnId] = React3__namespace.useState(
738
+ null
739
+ );
740
+ const [dragOverColumnPosition, setDragOverColumnPosition] = React3__namespace.useState(null);
741
+ const handleColumnDragStart = React3__namespace.useCallback(
742
+ (e, columnId) => {
743
+ setDraggedColumnId(columnId);
744
+ e.dataTransfer.effectAllowed = "move";
745
+ e.dataTransfer.setData("text/plain", columnId);
746
+ requestAnimationFrame(() => {
747
+ e.target.closest("th")?.classList.add("opacity-50");
748
+ });
749
+ },
750
+ []
751
+ );
752
+ const handleColumnDragOver = React3__namespace.useCallback(
753
+ (e, columnId) => {
754
+ e.preventDefault();
755
+ e.dataTransfer.dropEffect = "move";
756
+ if (draggedColumnId !== null && draggedColumnId !== columnId) {
757
+ const rect = e.currentTarget.getBoundingClientRect();
758
+ const midX = rect.left + rect.width / 2;
759
+ const position = e.clientX < midX ? "left" : "right";
760
+ setDragOverColumnId(columnId);
761
+ setDragOverColumnPosition(position);
762
+ }
763
+ },
764
+ [draggedColumnId]
765
+ );
766
+ const handleColumnDragLeave = React3__namespace.useCallback(() => {
767
+ setDragOverColumnId(null);
768
+ setDragOverColumnPosition(null);
769
+ }, []);
770
+ const handleColumnDrop = React3__namespace.useCallback(
771
+ (e, targetColumnId) => {
772
+ e.preventDefault();
773
+ if (draggedColumnId && draggedColumnId !== targetColumnId) {
774
+ const currentOrder = [...columnOrder];
775
+ const fromIndex = currentOrder.indexOf(draggedColumnId);
776
+ let toIndex = currentOrder.indexOf(targetColumnId);
777
+ if (fromIndex !== -1 && toIndex !== -1) {
778
+ currentOrder.splice(fromIndex, 1);
779
+ toIndex = currentOrder.indexOf(targetColumnId);
780
+ if (dragOverColumnPosition === "right") {
781
+ toIndex += 1;
782
+ }
783
+ currentOrder.splice(toIndex, 0, draggedColumnId);
784
+ setColumnOrder(currentOrder);
785
+ }
786
+ }
787
+ setDraggedColumnId(null);
788
+ setDragOverColumnId(null);
789
+ setDragOverColumnPosition(null);
790
+ },
791
+ [draggedColumnId, columnOrder, dragOverColumnPosition, setColumnOrder]
792
+ );
793
+ const handleColumnDragEnd = React3__namespace.useCallback((e) => {
794
+ e.target.closest("th")?.classList.remove("opacity-50");
795
+ setDraggedColumnId(null);
796
+ setDragOverColumnId(null);
797
+ setDragOverColumnPosition(null);
798
+ }, []);
799
+ const toggleColumnWrapping = React3__namespace.useCallback(
800
+ (columnId) => {
801
+ setColumnWrapping({
802
+ ...columnWrapping,
803
+ [columnId]: !columnWrapping[columnId]
804
+ });
805
+ },
806
+ [columnWrapping, setColumnWrapping]
807
+ );
808
+ const [draggedRowIndex, setDraggedRowIndex] = React3__namespace.useState(
809
+ null
810
+ );
811
+ const [dragOverRowIndex, setDragOverRowIndex] = React3__namespace.useState(
812
+ null
813
+ );
814
+ const [dragOverPosition, setDragOverPosition] = React3__namespace.useState(null);
815
+ const handleRowDragStart = React3__namespace.useCallback(
816
+ (e, rowIndex) => {
817
+ setDraggedRowIndex(rowIndex);
818
+ e.dataTransfer.effectAllowed = "move";
819
+ e.dataTransfer.setData("text/plain", String(rowIndex));
820
+ requestAnimationFrame(() => {
821
+ e.target.closest("tr")?.classList.add("opacity-50");
822
+ });
823
+ },
824
+ []
825
+ );
826
+ const handleRowDragOver = React3__namespace.useCallback(
827
+ (e, rowIndex) => {
828
+ e.preventDefault();
829
+ e.dataTransfer.dropEffect = "move";
830
+ if (draggedRowIndex !== null && draggedRowIndex !== rowIndex) {
831
+ const rect = e.currentTarget.getBoundingClientRect();
832
+ const midY = rect.top + rect.height / 2;
833
+ const position = e.clientY < midY ? "above" : "below";
834
+ setDragOverRowIndex(rowIndex);
835
+ setDragOverPosition(position);
836
+ }
837
+ },
838
+ [draggedRowIndex]
839
+ );
840
+ const handleRowDragLeave = React3__namespace.useCallback(() => {
841
+ setDragOverRowIndex(null);
842
+ setDragOverPosition(null);
843
+ }, []);
844
+ const handleRowDrop = React3__namespace.useCallback(
845
+ (e, toIndex) => {
846
+ e.preventDefault();
847
+ const fromIndex = draggedRowIndex;
848
+ if (fromIndex !== null && fromIndex !== toIndex && onRowDragEnd) {
849
+ let targetIndex = toIndex;
850
+ if (dragOverPosition === "below") {
851
+ targetIndex = toIndex + 1;
852
+ }
853
+ if (fromIndex < targetIndex) {
854
+ targetIndex -= 1;
855
+ }
856
+ if (fromIndex !== targetIndex) {
857
+ onRowDragEnd(fromIndex, targetIndex);
858
+ }
859
+ }
860
+ setDraggedRowIndex(null);
861
+ setDragOverRowIndex(null);
862
+ setDragOverPosition(null);
863
+ },
864
+ [draggedRowIndex, dragOverPosition, onRowDragEnd]
865
+ );
866
+ const handleRowDragEnd = React3__namespace.useCallback((e) => {
867
+ e.target.closest("tr")?.classList.remove("opacity-50");
868
+ setDraggedRowIndex(null);
869
+ setDragOverRowIndex(null);
870
+ setDragOverPosition(null);
871
+ }, []);
872
+ const handleResizeStart = React3__namespace.useCallback(
873
+ (columnId, startX, startWidth) => {
874
+ setResizingColumn(columnId);
875
+ const handleMouseMove = (e) => {
876
+ const delta = e.clientX - startX;
877
+ const newWidth = Math.max(20, startWidth + delta);
878
+ setColumnSizing((prev) => ({ ...prev, [columnId]: newWidth }));
879
+ };
880
+ const handleMouseUp = () => {
881
+ setResizingColumn(null);
882
+ document.removeEventListener("mousemove", handleMouseMove);
883
+ document.removeEventListener("mouseup", handleMouseUp);
884
+ document.body.style.cursor = "";
885
+ document.body.style.userSelect = "";
886
+ };
887
+ document.body.style.cursor = "col-resize";
888
+ document.body.style.userSelect = "none";
889
+ document.addEventListener("mousemove", handleMouseMove);
890
+ document.addEventListener("mouseup", handleMouseUp);
891
+ },
892
+ []
893
+ );
894
+ const contextValue = React3__namespace.useMemo(
895
+ () => ({
896
+ columnWrapping,
897
+ toggleColumnWrapping,
898
+ enableColumnDrag: enableColumnDrag ?? false,
899
+ onColumnDragStart: handleColumnDragStart,
900
+ onColumnDragEnd: handleColumnDragEnd,
901
+ fontSize,
902
+ fontSizeClass,
903
+ density
904
+ }),
905
+ [
906
+ columnWrapping,
907
+ toggleColumnWrapping,
908
+ enableColumnDrag,
909
+ handleColumnDragStart,
910
+ handleColumnDragEnd,
911
+ fontSize,
912
+ fontSizeClass,
913
+ density
914
+ ]
915
+ );
916
+ return /* @__PURE__ */ jsxRuntime.jsx(DataTableContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
917
+ "div",
918
+ {
919
+ className: chunkADIDI7AJ_js.cn(
920
+ "flex w-full max-w-full min-w-0 flex-col gap-2.5",
921
+ className
922
+ ),
923
+ ...props,
924
+ children: [
925
+ children,
926
+ filters && filters.length > 0 || onAddFilter ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1", children: /* @__PURE__ */ jsxRuntime.jsx(
927
+ DataTableFilterBadges,
928
+ {
929
+ filters: filters ?? [],
930
+ onRemoveFilter: (id) => onRemoveFilter?.(id),
931
+ onChangeFilter: (id, value) => onChangeFilter?.(id, value),
932
+ onClearAll: onClearAllFilters,
933
+ onAddFilter
934
+ }
935
+ ) }) : null,
936
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkADIDI7AJ_js.cn("mx-1", fontSizeClass), children: /* @__PURE__ */ jsxRuntime.jsx(
937
+ "div",
938
+ {
939
+ className: chunkADIDI7AJ_js.cn(
940
+ "overflow-x-auto rounded-t-md [&::-webkit-scrollbar-track]:bg-transparent",
941
+ summary ? "border-t" : "border rounded-b-md"
942
+ ),
943
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
944
+ "table",
945
+ {
946
+ className: chunkADIDI7AJ_js.cn(
947
+ "caption-bottom border-separate border-spacing-0",
948
+ fontSizeClass
949
+ ),
950
+ style: {
951
+ width: `max(100%, ${renderedTableWidth}px)`,
952
+ tableLayout: "fixed"
953
+ },
954
+ children: [
955
+ /* @__PURE__ */ jsxRuntime.jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => {
956
+ const renderableHeaders = headerGroup.headers.filter(
957
+ (h) => !((rowSelectionStyle === "hover" || enableRowDrag) && h.id === "select")
958
+ );
959
+ const orderedHeaders = enableColumnDrag ? [...renderableHeaders].sort((a, b) => {
960
+ const aIndex = columnOrder.indexOf(a.id);
961
+ const bIndex = columnOrder.indexOf(b.id);
962
+ if (aIndex === -1) return 1;
963
+ if (bIndex === -1) return -1;
964
+ return aIndex - bIndex;
965
+ }) : renderableHeaders;
966
+ return /* @__PURE__ */ jsxRuntime.jsxs(
967
+ TableRow,
968
+ {
969
+ className: "hover:bg-transparent",
970
+ children: [
971
+ (rowSelectionStyle === "hover" || enableRowDrag) && /* @__PURE__ */ jsxRuntime.jsx(
972
+ TableHead,
973
+ {
974
+ className: chunkADIDI7AJ_js.cn(
975
+ "p-0 border-r-0 whitespace-nowrap border-l border-b border-border group/header-gutter",
976
+ headerHeight
977
+ ),
978
+ style: { width: "1%" },
979
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-0.5 px-1 h-full", children: [
980
+ enableRowDrag && /* @__PURE__ */ jsxRuntime.jsx(
981
+ "div",
982
+ {
983
+ className: chunkADIDI7AJ_js.cn(
984
+ "shrink-0",
985
+ density === "compact" ? "size-5" : "size-6"
986
+ ),
987
+ "aria-hidden": "true"
988
+ }
989
+ ),
990
+ /* @__PURE__ */ jsxRuntime.jsxs(
991
+ "button",
992
+ {
993
+ type: "button",
994
+ onClick: () => table.toggleAllPageRowsSelected(
995
+ !table.getIsAllPageRowsSelected()
996
+ ),
997
+ className: chunkADIDI7AJ_js.cn(
998
+ "flex items-center justify-center rounded border transition-all",
999
+ checkboxSize,
1000
+ table.getIsAllPageRowsSelected() ? "bg-primary border-primary text-primary-foreground opacity-100" : table.getIsSomePageRowsSelected() ? "bg-primary/50 border-primary text-primary-foreground opacity-100" : "border-border hover:border-primary/50 hover:bg-accent opacity-0 group-hover/header-gutter:opacity-100"
1001
+ ),
1002
+ "aria-label": table.getIsAllPageRowsSelected() ? "Deselect all rows" : "Select all rows",
1003
+ children: [
1004
+ table.getIsAllPageRowsSelected() && /* @__PURE__ */ jsxRuntime.jsx(
1005
+ "svg",
1006
+ {
1007
+ className: checkmarkSize,
1008
+ viewBox: "0 0 12 12",
1009
+ fill: "none",
1010
+ "aria-hidden": "true",
1011
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1012
+ "path",
1013
+ {
1014
+ d: "M2.5 6L5 8.5L9.5 3.5",
1015
+ stroke: "currentColor",
1016
+ strokeWidth: "2",
1017
+ strokeLinecap: "round",
1018
+ strokeLinejoin: "round"
1019
+ }
1020
+ )
1021
+ }
1022
+ ),
1023
+ table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected() && /* @__PURE__ */ jsxRuntime.jsx(
1024
+ "svg",
1025
+ {
1026
+ className: checkmarkSize,
1027
+ viewBox: "0 0 12 12",
1028
+ fill: "none",
1029
+ "aria-hidden": "true",
1030
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1031
+ "path",
1032
+ {
1033
+ d: "M2.5 6H9.5",
1034
+ stroke: "currentColor",
1035
+ strokeWidth: "2",
1036
+ strokeLinecap: "round"
1037
+ }
1038
+ )
1039
+ }
1040
+ )
1041
+ ]
1042
+ }
1043
+ )
1044
+ ] })
1045
+ }
1046
+ ),
1047
+ orderedHeaders.map((header, headerIndex) => {
1048
+ const isLastColumn = headerIndex === orderedHeaders.length - 1;
1049
+ const hasGutter = rowSelectionStyle === "hover" || enableRowDrag;
1050
+ const isFirstColumn = headerIndex === 0 && !hasGutter;
1051
+ const headerLeafColumnIds = header.getLeafHeaders().map((leafHeader) => leafHeader.column.id).filter(
1052
+ (columnId) => renderedLeafIndexById.has(columnId)
1053
+ );
1054
+ const stickyHeaderLeafIds = headerLeafColumnIds.filter(
1055
+ (columnId) => stickyColumnIds.has(columnId)
1056
+ );
1057
+ const isStickyColumn = headerLeafColumnIds.length > 0 && stickyHeaderLeafIds.length === headerLeafColumnIds.length;
1058
+ const stickyHeaderColumnId = isStickyColumn ? stickyHeaderLeafIds.sort(
1059
+ (a, b) => (renderedLeafIndexById.get(a) ?? 0) - (renderedLeafIndexById.get(b) ?? 0)
1060
+ )[0] : void 0;
1061
+ const stickyLeft = stickyHeaderColumnId ? stickyColumnLefts.get(stickyHeaderColumnId) ?? 0 : 0;
1062
+ const headerDef = header.column.columnDef.header;
1063
+ const isSimpleHeader = typeof headerDef === "string";
1064
+ const colDef = header.column.columnDef;
1065
+ const isFixedWidth = colDef.size && colDef.minSize === colDef.size && colDef.maxSize === colDef.size;
1066
+ const isActionsColumn = header.id === "actions" || header.id === "select";
1067
+ const resizedWidth = isFixedWidth ? void 0 : columnSizing[header.id];
1068
+ const canDragColumn = enableColumnDrag && !isFixedWidth && !isActionsColumn;
1069
+ const isDragOverLeft = dragOverColumnId === header.id && dragOverColumnPosition === "left";
1070
+ const isDragOverRight = dragOverColumnId === header.id && dragOverColumnPosition === "right";
1071
+ const firstLeafIndex = Math.min(
1072
+ ...headerLeafColumnIds.map(
1073
+ (columnId) => renderedLeafIndexById.get(columnId) ?? 0
1074
+ )
1075
+ );
1076
+ const isFirstNonStickyAfterSticky = !isStickyColumn && firstLeafIndex > 0 && stickyColumnIds.has(
1077
+ renderedLeafColumns[firstLeafIndex - 1]?.id ?? ""
1078
+ );
1079
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1080
+ TableHead,
1081
+ {
1082
+ "data-sticky-column": isStickyColumn ? "true" : void 0,
1083
+ colSpan: header.colSpan,
1084
+ onDragOver: canDragColumn ? (e) => handleColumnDragOver(e, header.id) : void 0,
1085
+ onDragLeave: canDragColumn ? handleColumnDragLeave : void 0,
1086
+ onDrop: canDragColumn ? (e) => handleColumnDrop(e, header.id) : void 0,
1087
+ className: chunkADIDI7AJ_js.cn(
1088
+ isSimpleHeader ? "px-2" : "p-0",
1089
+ // Add padding for simple headers, let component headers handle their own
1090
+ headerHeight,
1091
+ "relative",
1092
+ "overflow-hidden text-ellipsis border-b border-border",
1093
+ !columnWrapping[header.id] && "whitespace-nowrap",
1094
+ columnWrapping[header.id] && "whitespace-normal",
1095
+ isFirstColumn && "border-l border-border",
1096
+ !isStickyColumn && "border-r border-border",
1097
+ isStickyColumn && "border-r border-border",
1098
+ isFirstNonStickyAfterSticky && "border-l border-border",
1099
+ isDragOverLeft && "border-l-2 border-l-primary",
1100
+ isDragOverRight && "border-r-2 border-r-primary"
1101
+ ),
1102
+ style: {
1103
+ ...isActionsColumn ? { width: "1%" } : {
1104
+ width: resizedWidth ?? header.getSize(),
1105
+ minWidth: header.column.columnDef.minSize,
1106
+ maxWidth: header.column.columnDef.maxSize
1107
+ },
1108
+ ...isStickyColumn ? {
1109
+ position: "sticky",
1110
+ left: stickyLeft,
1111
+ zIndex: 60,
1112
+ background: "hsl(var(--background) / 1)",
1113
+ backgroundColor: "hsl(var(--background) / 1)",
1114
+ opacity: 1,
1115
+ backgroundClip: "padding-box",
1116
+ boxShadow: "inset -1px 0 0 hsl(var(--border)), inset 0 -1px 0 hsl(var(--border))",
1117
+ isolation: "isolate",
1118
+ contain: "paint",
1119
+ backfaceVisibility: "hidden",
1120
+ mixBlendMode: "normal",
1121
+ backdropFilter: "none",
1122
+ WebkitBackdropFilter: "none",
1123
+ transform: "translateZ(0)",
1124
+ WebkitTransform: "translateZ(0)"
1125
+ } : {}
1126
+ },
1127
+ children: [
1128
+ isStickyColumn && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-x-0 top-0 bottom-px z-0 bg-background" }),
1129
+ header.isPlaceholder ? null : /* @__PURE__ */ jsxRuntime.jsxs(
1130
+ "div",
1131
+ {
1132
+ className: chunkADIDI7AJ_js.cn(
1133
+ "relative z-10",
1134
+ enableTreeView && headerIndex === 0 && "flex items-center"
1135
+ ),
1136
+ children: [
1137
+ enableTreeView && headerIndex === 0 && /* @__PURE__ */ jsxRuntime.jsx(
1138
+ TreeExpandCycleButton,
1139
+ {
1140
+ table,
1141
+ density
1142
+ }
1143
+ ),
1144
+ isSimpleHeader ? /* @__PURE__ */ jsxRuntime.jsx(
1145
+ "span",
1146
+ {
1147
+ className: chunkADIDI7AJ_js.cn("font-medium", fontSizeClass),
1148
+ children: headerDef
1149
+ }
1150
+ ) : reactTable.flexRender(
1151
+ header.column.columnDef.header,
1152
+ header.getContext()
1153
+ )
1154
+ ]
1155
+ }
1156
+ ),
1157
+ enableColumnResizing && !isLastColumn && !isFixedWidth && // biome-ignore lint/a11y/noStaticElementInteractions: Column resize uses mouse drag interaction only
1158
+ /* @__PURE__ */ jsxRuntime.jsx(
1159
+ "div",
1160
+ {
1161
+ onMouseDown: (e) => {
1162
+ e.preventDefault();
1163
+ e.stopPropagation();
1164
+ const th = e.currentTarget.parentElement;
1165
+ if (th) {
1166
+ handleResizeStart(
1167
+ header.id,
1168
+ e.clientX,
1169
+ th.offsetWidth
1170
+ );
1171
+ }
1172
+ },
1173
+ className: chunkADIDI7AJ_js.cn(
1174
+ "absolute -right-1 top-0 z-10 h-full w-3 cursor-col-resize select-none",
1175
+ "before:absolute before:right-1 before:top-0 before:h-full before:w-px before:bg-transparent before:transition-colors",
1176
+ "hover:before:bg-primary/50",
1177
+ resizingColumn === header.id && "before:bg-primary"
1178
+ )
1179
+ }
1180
+ )
1181
+ ]
1182
+ },
1183
+ header.id
1184
+ );
1185
+ })
1186
+ ]
1187
+ },
1188
+ headerGroup.id
1189
+ );
1190
+ }) }),
1191
+ /* @__PURE__ */ jsxRuntime.jsx(
1192
+ TableBody,
1193
+ {
1194
+ className: summary ? "[&_tr:last-child]:border-b" : void 0,
1195
+ children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row, rowIndex) => {
1196
+ const isHovered = hoveredRowId === row.id;
1197
+ const isSelected = row.getIsSelected();
1198
+ const showRowControls = isHovered || isSelected;
1199
+ const isDragOverAbove = dragOverRowIndex === rowIndex && dragOverPosition === "above";
1200
+ const isDragOverBelow = dragOverRowIndex === rowIndex && dragOverPosition === "below";
1201
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1202
+ TableRow,
1203
+ {
1204
+ "data-state": isSelected && "selected",
1205
+ "data-hovered": isHovered,
1206
+ onMouseEnter: () => setHoveredRowId(row.id),
1207
+ onMouseLeave: () => setHoveredRowId(null),
1208
+ onClick: () => onRowClick?.(row),
1209
+ onDragOver: enableRowDrag ? (e) => handleRowDragOver(e, rowIndex) : void 0,
1210
+ onDragLeave: enableRowDrag ? handleRowDragLeave : void 0,
1211
+ onDrop: enableRowDrag ? (e) => handleRowDrop(e, rowIndex) : void 0,
1212
+ className: chunkADIDI7AJ_js.cn(
1213
+ "group/row",
1214
+ onRowClick && "cursor-pointer hover:bg-muted/50",
1215
+ getRowClassName2?.(row),
1216
+ // Add bottom border to last row when summary exists
1217
+ summary && rowIndex === table.getRowModel().rows.length - 1 && "border-b"
1218
+ ),
1219
+ children: [
1220
+ (rowSelectionStyle === "hover" || enableRowDrag) && /* @__PURE__ */ jsxRuntime.jsx(
1221
+ TableCell,
1222
+ {
1223
+ className: chunkADIDI7AJ_js.cn(
1224
+ "p-0 border-r-0 whitespace-nowrap border-l border-border",
1225
+ // All rows get bottom border except last row without summary
1226
+ rowIndex !== table.getRowModel().rows.length - 1 && "border-b border-border",
1227
+ // Last row only gets border-b when summary exists, plus rounding
1228
+ summary && rowIndex === table.getRowModel().rows.length - 1 && "border-b border-border rounded-bl-md overflow-hidden",
1229
+ // Drag-over indicator
1230
+ isDragOverAbove && "border-t-2 border-t-primary",
1231
+ isDragOverBelow && "border-b-2 border-b-primary"
1232
+ ),
1233
+ style: { width: "1%" },
1234
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1235
+ "div",
1236
+ {
1237
+ className: chunkADIDI7AJ_js.cn(
1238
+ "flex items-center justify-end gap-0.5 px-1 h-full transition-opacity",
1239
+ showRowControls ? "opacity-100" : "opacity-0"
1240
+ ),
1241
+ children: [
1242
+ enableRowDrag && /* @__PURE__ */ jsxRuntime.jsx(
1243
+ "div",
1244
+ {
1245
+ draggable: true,
1246
+ onDragStart: (e) => handleRowDragStart(e, rowIndex),
1247
+ onDragEnd: handleRowDragEnd,
1248
+ className: chunkADIDI7AJ_js.cn(
1249
+ "flex items-center justify-center text-muted-foreground/50 hover:text-muted-foreground cursor-grab active:cursor-grabbing rounded hover:bg-accent",
1250
+ density === "compact" ? "size-5" : "size-6"
1251
+ ),
1252
+ "aria-hidden": "true",
1253
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1254
+ lucideReact.GripVertical,
1255
+ {
1256
+ className: density === "compact" ? "size-3" : "size-4"
1257
+ }
1258
+ )
1259
+ }
1260
+ ),
1261
+ /* @__PURE__ */ jsxRuntime.jsx(
1262
+ "button",
1263
+ {
1264
+ type: "button",
1265
+ onClick: () => row.toggleSelected(!row.getIsSelected()),
1266
+ className: chunkADIDI7AJ_js.cn(
1267
+ "flex items-center justify-center rounded border transition-colors",
1268
+ checkboxSize,
1269
+ isSelected ? "bg-primary border-primary text-primary-foreground" : "border-border hover:border-primary/50 hover:bg-accent"
1270
+ ),
1271
+ "aria-label": isSelected ? "Deselect row" : "Select row",
1272
+ children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
1273
+ "svg",
1274
+ {
1275
+ className: checkmarkSize,
1276
+ viewBox: "0 0 12 12",
1277
+ fill: "none",
1278
+ "aria-hidden": "true",
1279
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1280
+ "path",
1281
+ {
1282
+ d: "M2.5 6L5 8.5L9.5 3.5",
1283
+ stroke: "currentColor",
1284
+ strokeWidth: "2",
1285
+ strokeLinecap: "round",
1286
+ strokeLinejoin: "round"
1287
+ }
1288
+ )
1289
+ }
1290
+ )
1291
+ }
1292
+ )
1293
+ ]
1294
+ }
1295
+ )
1296
+ }
1297
+ ),
1298
+ row.getVisibleCells().map((cell) => {
1299
+ if ((rowSelectionStyle === "hover" || enableRowDrag) && cell.column.id === "select") {
1300
+ return null;
1301
+ }
1302
+ return cell;
1303
+ }).filter(
1304
+ (cell) => cell !== null
1305
+ ).sort((a, b) => {
1306
+ if (!enableColumnDrag) return 0;
1307
+ const aIndex = columnOrder.indexOf(a.column.id);
1308
+ const bIndex = columnOrder.indexOf(b.column.id);
1309
+ if (aIndex === -1) return 1;
1310
+ if (bIndex === -1) return -1;
1311
+ return aIndex - bIndex;
1312
+ }).map((cell, cellIndex, sortedCells) => {
1313
+ const isLastColumn = cellIndex === sortedCells.length - 1;
1314
+ const hasGutter = rowSelectionStyle === "hover" || enableRowDrag;
1315
+ const isFirstColumn = cellIndex === 0 && !hasGutter;
1316
+ const isStickyCell = stickyColumnIds.has(
1317
+ cell.column.id
1318
+ );
1319
+ const stickyLeft = stickyColumnLefts.get(cell.column.id) ?? 0;
1320
+ const isFirstNonStickyAfterSticky = !isStickyCell && cellIndex > 0 && stickyColumnIds.has(
1321
+ sortedCells[cellIndex - 1]?.column.id ?? ""
1322
+ );
1323
+ const colDef = cell.column.columnDef;
1324
+ const isFixedWidth = colDef.size && colDef.minSize === colDef.size && colDef.maxSize === colDef.size;
1325
+ const isActionsColumn = cell.column.id === "actions" || cell.column.id === "select";
1326
+ const resizedWidth = isFixedWidth ? void 0 : columnSizing[cell.column.id];
1327
+ const isWrapped = columnWrapping[cell.column.id];
1328
+ const colMeta = cell.column.columnDef.meta;
1329
+ const colAlign = colMeta?.align ?? "left";
1330
+ const allowHorizontalScroll = colMeta?.allowHorizontalScroll === true;
1331
+ const alignClass = colAlign === "right" ? "text-right" : colAlign === "center" ? "text-center" : "";
1332
+ const isFirstDataCell = cellIndex === 0;
1333
+ const showTreeUI = enableTreeView && isFirstDataCell;
1334
+ const treeIndent = showTreeUI ? row.depth * treeIndentPx : 0;
1335
+ const canExpand = showTreeUI && row.getCanExpand();
1336
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1337
+ TableCell,
1338
+ {
1339
+ "data-sticky-column": isStickyCell ? "true" : void 0,
1340
+ className: chunkADIDI7AJ_js.cn(
1341
+ cellPadding,
1342
+ isStickyCell && "relative",
1343
+ !isWrapped && "overflow-hidden text-ellipsis whitespace-nowrap",
1344
+ isWrapped && "whitespace-normal break-words",
1345
+ !isLastColumn && !isStickyCell && "border-r border-border",
1346
+ isStickyCell && "border-r border-border",
1347
+ isFirstColumn && "border-l border-border",
1348
+ isFirstNonStickyAfterSticky && "border-l border-border",
1349
+ isLastColumn && "border-r border-border",
1350
+ isActionsColumn && "whitespace-nowrap",
1351
+ // All rows get bottom border except last row without summary
1352
+ rowIndex !== table.getRowModel().rows.length - 1 && "border-b border-border",
1353
+ // Last row only gets border-b when summary exists, plus rounding on corners
1354
+ summary && rowIndex === table.getRowModel().rows.length - 1 && "border-b border-border",
1355
+ summary && rowIndex === table.getRowModel().rows.length - 1 && isLastColumn && "rounded-br-md overflow-hidden",
1356
+ summary && rowIndex === table.getRowModel().rows.length - 1 && isFirstColumn && "rounded-bl-md overflow-hidden"
1357
+ ),
1358
+ style: {
1359
+ width: resizedWidth || cell.column.getSize(),
1360
+ minWidth: cell.column.columnDef.minSize,
1361
+ maxWidth: cell.column.columnDef.maxSize,
1362
+ ...isStickyCell ? {
1363
+ position: "sticky",
1364
+ left: stickyLeft,
1365
+ zIndex: 50,
1366
+ background: "hsl(var(--background) / 1)",
1367
+ backgroundColor: "hsl(var(--background) / 1)",
1368
+ opacity: 1,
1369
+ backgroundClip: "padding-box",
1370
+ boxShadow: "inset 0 0 0 9999px hsl(var(--background)), inset -1px 0 0 hsl(var(--border))",
1371
+ borderBottom: "1px solid hsl(var(--border))",
1372
+ isolation: "isolate",
1373
+ contain: "paint",
1374
+ backfaceVisibility: "hidden",
1375
+ mixBlendMode: "normal",
1376
+ backdropFilter: "none",
1377
+ WebkitBackdropFilter: "none",
1378
+ transform: "translateZ(0)",
1379
+ WebkitTransform: "translateZ(0)"
1380
+ } : {}
1381
+ },
1382
+ children: [
1383
+ isStickyCell && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-0 z-0 border-b border-border bg-background" }),
1384
+ showTreeUI ? /* @__PURE__ */ jsxRuntime.jsxs(
1385
+ "div",
1386
+ {
1387
+ className: "relative z-10 flex items-center gap-1",
1388
+ style: { paddingLeft: `${treeIndent}px` },
1389
+ children: [
1390
+ canExpand ? /* @__PURE__ */ jsxRuntime.jsx(
1391
+ "button",
1392
+ {
1393
+ type: "button",
1394
+ onClick: (e) => {
1395
+ e.stopPropagation();
1396
+ row.toggleExpanded();
1397
+ },
1398
+ className: "shrink-0 text-muted-foreground hover:text-foreground",
1399
+ "aria-label": row.getIsExpanded() ? "Collapse" : "Expand",
1400
+ children: row.getIsExpanded() ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4" })
1401
+ }
1402
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1403
+ "span",
1404
+ {
1405
+ className: "inline-block shrink-0 size-4",
1406
+ "aria-hidden": "true"
1407
+ }
1408
+ ),
1409
+ /* @__PURE__ */ jsxRuntime.jsx(
1410
+ "div",
1411
+ {
1412
+ className: chunkADIDI7AJ_js.cn(
1413
+ "min-w-0",
1414
+ !isWrapped && !allowHorizontalScroll && "truncate",
1415
+ allowHorizontalScroll && "overflow-x-auto whitespace-nowrap [&::-webkit-scrollbar]:hidden"
1416
+ ),
1417
+ style: allowHorizontalScroll ? {
1418
+ scrollbarWidth: "none",
1419
+ msOverflowStyle: "none"
1420
+ } : void 0,
1421
+ children: reactTable.flexRender(
1422
+ cell.column.columnDef.cell,
1423
+ cell.getContext()
1424
+ )
1425
+ }
1426
+ )
1427
+ ]
1428
+ }
1429
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1430
+ "div",
1431
+ {
1432
+ className: chunkADIDI7AJ_js.cn(
1433
+ "relative z-10",
1434
+ !isWrapped && !allowHorizontalScroll && "truncate",
1435
+ allowHorizontalScroll && "overflow-x-auto whitespace-nowrap [&::-webkit-scrollbar]:hidden",
1436
+ alignClass
1437
+ ),
1438
+ style: allowHorizontalScroll ? {
1439
+ scrollbarWidth: "none",
1440
+ msOverflowStyle: "none"
1441
+ } : void 0,
1442
+ children: reactTable.flexRender(
1443
+ cell.column.columnDef.cell,
1444
+ cell.getContext()
1445
+ )
1446
+ }
1447
+ )
1448
+ ]
1449
+ },
1450
+ cell.id
1451
+ );
1452
+ })
1453
+ ]
1454
+ },
1455
+ row.id
1456
+ );
1457
+ }) : /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx(
1458
+ TableCell,
1459
+ {
1460
+ colSpan: columns.length + (rowSelectionStyle === "hover" || enableRowDrag ? 1 : 0),
1461
+ className: "h-24",
1462
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky left-0 w-fit px-4 text-muted-foreground", children: "No results." })
1463
+ }
1464
+ ) })
1465
+ }
1466
+ ),
1467
+ summary && /* @__PURE__ */ jsxRuntime.jsx("tfoot", { children: summary })
1468
+ ]
1469
+ }
1470
+ )
1471
+ }
1472
+ ) }),
1473
+ actionBar && table.getFilteredSelectedRowModel().rows.length > 0 && actionBar,
1474
+ floatingBar && table.getFilteredSelectedRowModel().rows.length > 0 && floatingBar
1475
+ ]
1476
+ }
1477
+ ) });
1478
+ }
1479
+ var defaultColumnIcons = {
1480
+ text: lucideReact.Text,
1481
+ number: lucideReact.Hash,
1482
+ date: lucideReact.Calendar,
1483
+ boolean: lucideReact.CheckSquare,
1484
+ enum: lucideReact.List,
1485
+ custom: lucideReact.Text
1486
+ };
1487
+ function getColumnIcon(column, propIcon, propColumnType) {
1488
+ const meta = column.columnDef.meta;
1489
+ if (propIcon) return propIcon;
1490
+ if (meta?.icon) return meta.icon;
1491
+ const columnType = propColumnType ?? meta?.columnType;
1492
+ if (columnType) return defaultColumnIcons[columnType];
1493
+ return void 0;
1494
+ }
1495
+ function DataTableColumnHeader({
1496
+ column,
1497
+ title,
1498
+ className,
1499
+ columnType,
1500
+ icon,
1501
+ filterable,
1502
+ filterType,
1503
+ filterOptions,
1504
+ onFilterChange,
1505
+ isWrapped: isWrappedProp,
1506
+ onToggleWrap: onToggleWrapProp,
1507
+ customMenuItems
1508
+ }) {
1509
+ const meta = column.columnDef.meta;
1510
+ const dataTableContext = useDataTableContext();
1511
+ const isWrapped = isWrappedProp ?? dataTableContext?.columnWrapping[column.id] ?? false;
1512
+ const onToggleWrap = onToggleWrapProp ?? (() => dataTableContext?.toggleColumnWrapping(column.id));
1513
+ const canSort = column.getCanSort();
1514
+ const canHide = column.getCanHide();
1515
+ const isSorted = column.getIsSorted();
1516
+ const isFiltered = column.getIsFiltered();
1517
+ const Icon = getColumnIcon(column, icon, columnType);
1518
+ const showFilter = filterable ?? meta?.filterable ?? false;
1519
+ const resolvedFilterType = filterType ?? meta?.filterType ?? "text";
1520
+ const resolvedFilterOptions = filterOptions ?? meta?.filterOptions;
1521
+ const filterPlaceholder = meta?.filterPlaceholder;
1522
+ const [isOpen, setIsOpen] = React3__namespace.useState(false);
1523
+ const mouseDownPosRef = React3__namespace.useRef(null);
1524
+ const didDragRef = React3__namespace.useRef(false);
1525
+ const canDrag = dataTableContext?.enableColumnDrag ?? false;
1526
+ const handleMouseDown = (e) => {
1527
+ mouseDownPosRef.current = { x: e.clientX, y: e.clientY };
1528
+ didDragRef.current = false;
1529
+ };
1530
+ const handleDragStart = (e) => {
1531
+ didDragRef.current = true;
1532
+ mouseDownPosRef.current = null;
1533
+ dataTableContext?.onColumnDragStart(e, column.id);
1534
+ };
1535
+ const handleDragEnd = (e) => {
1536
+ dataTableContext?.onColumnDragEnd(e);
1537
+ };
1538
+ const handleClick = (e) => {
1539
+ if (!didDragRef.current && mouseDownPosRef.current) {
1540
+ const dx = Math.abs(e.clientX - mouseDownPosRef.current.x);
1541
+ const dy = Math.abs(e.clientY - mouseDownPosRef.current.y);
1542
+ if (dx < 5 && dy < 5) {
1543
+ setIsOpen(true);
1544
+ }
1545
+ }
1546
+ mouseDownPosRef.current = null;
1547
+ didDragRef.current = false;
1548
+ };
1549
+ const colAlign = meta?.align ?? "left";
1550
+ const justifyClass = colAlign === "right" ? "justify-end" : colAlign === "center" ? "justify-center" : "";
1551
+ if (!canSort && !canHide && !showFilter) {
1552
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1553
+ "div",
1554
+ {
1555
+ className: chunkADIDI7AJ_js.cn(
1556
+ "flex items-center gap-1.5 px-2 h-full",
1557
+ justifyClass,
1558
+ canDrag && "cursor-grab",
1559
+ className
1560
+ ),
1561
+ draggable: canDrag,
1562
+ onDragStart: canDrag ? handleDragStart : void 0,
1563
+ onDragEnd: canDrag ? handleDragEnd : void 0,
1564
+ "aria-hidden": canDrag ? "true" : void 0,
1565
+ children: [
1566
+ Icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4 text-muted-foreground" }),
1567
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: title })
1568
+ ]
1569
+ }
1570
+ );
1571
+ }
1572
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkADIDI7AJ_js.cn("flex h-full items-center w-full", className), children: /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, modal: false, children: [
1573
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full", style: { pointerEvents: "none" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
1574
+ "button",
1575
+ {
1576
+ type: "button",
1577
+ draggable: canDrag,
1578
+ onMouseDown: handleMouseDown,
1579
+ onDragStart: canDrag ? handleDragStart : void 0,
1580
+ onDragEnd: canDrag ? handleDragEnd : void 0,
1581
+ onClick: handleClick,
1582
+ style: { pointerEvents: "auto" },
1583
+ className: chunkADIDI7AJ_js.cn(
1584
+ "relative flex items-center gap-1.5 w-full h-full px-2",
1585
+ justifyClass || "text-left",
1586
+ "before:absolute before:-inset-[99px] before:-z-10 before:pointer-events-none before:transition-colors hover:before:bg-accent/50",
1587
+ isOpen && "before:bg-accent",
1588
+ "focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
1589
+ canDrag ? "cursor-grab" : "cursor-pointer"
1590
+ ),
1591
+ children: [
1592
+ Icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-3.5 text-muted-foreground shrink-0" }),
1593
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: title }),
1594
+ isFiltered && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "size-3 text-primary shrink-0" }),
1595
+ isSorted === "desc" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "size-3.5 text-muted-foreground shrink-0" }),
1596
+ isSorted === "asc" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "size-3.5 text-muted-foreground shrink-0" })
1597
+ ]
1598
+ }
1599
+ ) }) }),
1600
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenuContent, { align: "start", className: "w-36", children: [
1601
+ customMenuItems && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1602
+ customMenuItems,
1603
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuSeparator, {})
1604
+ ] }),
1605
+ showFilter && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1606
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenuSub, { children: [
1607
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenuSubTrigger, { className: "text-xs", children: [
1608
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "mr-2 size-3.5 text-muted-foreground" }),
1609
+ "Filter",
1610
+ isFiltered && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto text-[10px] text-muted-foreground", children: "Active" })
1611
+ ] }),
1612
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuSubContent, { alignOffset: -5, sideOffset: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
1613
+ DataTableColumnFilterContent,
1614
+ {
1615
+ title,
1616
+ value: column.getFilterValue(),
1617
+ onChange: (v) => {
1618
+ column.setFilterValue(v);
1619
+ onFilterChange?.(column.id, v);
1620
+ },
1621
+ onClear: () => column.setFilterValue(void 0),
1622
+ filterType: resolvedFilterType,
1623
+ filterOptions: resolvedFilterOptions,
1624
+ placeholder: filterPlaceholder,
1625
+ showDeleteMenu: false
1626
+ }
1627
+ ) })
1628
+ ] }),
1629
+ isFiltered && /* @__PURE__ */ jsxRuntime.jsx(
1630
+ chunkJ6OLBSZR_js.DropdownMenuItem,
1631
+ {
1632
+ onClick: () => column.setFilterValue(void 0),
1633
+ className: "text-xs",
1634
+ children: "Clear filter"
1635
+ }
1636
+ ),
1637
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuSeparator, {})
1638
+ ] }),
1639
+ canSort && /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenuSub, { children: [
1640
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenuSubTrigger, { className: "text-xs", children: [
1641
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListOrdered, { className: "mr-2 size-3.5 text-muted-foreground" }),
1642
+ "Sort"
1643
+ ] }),
1644
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenuSubContent, { alignOffset: -5, sideOffset: 5, children: [
1645
+ /* @__PURE__ */ jsxRuntime.jsxs(
1646
+ chunkJ6OLBSZR_js.DropdownMenuItem,
1647
+ {
1648
+ onClick: () => column.toggleSorting(false),
1649
+ className: chunkADIDI7AJ_js.cn("text-xs", isSorted === "asc" && "bg-accent"),
1650
+ children: [
1651
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "mr-2 size-3.5 text-muted-foreground" }),
1652
+ "Ascending"
1653
+ ]
1654
+ }
1655
+ ),
1656
+ /* @__PURE__ */ jsxRuntime.jsxs(
1657
+ chunkJ6OLBSZR_js.DropdownMenuItem,
1658
+ {
1659
+ onClick: () => column.toggleSorting(true),
1660
+ className: chunkADIDI7AJ_js.cn("text-xs", isSorted === "desc" && "bg-accent"),
1661
+ children: [
1662
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "mr-2 size-3.5 text-muted-foreground" }),
1663
+ "Descending"
1664
+ ]
1665
+ }
1666
+ ),
1667
+ isSorted && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1668
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuSeparator, {}),
1669
+ /* @__PURE__ */ jsxRuntime.jsx(
1670
+ chunkJ6OLBSZR_js.DropdownMenuItem,
1671
+ {
1672
+ onClick: () => column.clearSorting(),
1673
+ className: "text-xs",
1674
+ children: "Clear sort"
1675
+ }
1676
+ )
1677
+ ] })
1678
+ ] })
1679
+ ] }),
1680
+ (dataTableContext || onToggleWrapProp) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1681
+ /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuSeparator, {}),
1682
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkJ6OLBSZR_js.DropdownMenuItem, { onClick: onToggleWrap, className: "text-xs", children: [
1683
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WrapText, { className: "mr-2 size-3.5 text-muted-foreground" }),
1684
+ isWrapped ? "Disable wrap" : "Wrap text"
1685
+ ] })
1686
+ ] }),
1687
+ canHide && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1688
+ (canSort || dataTableContext || onToggleWrapProp) && /* @__PURE__ */ jsxRuntime.jsx(chunkJ6OLBSZR_js.DropdownMenuSeparator, {}),
1689
+ /* @__PURE__ */ jsxRuntime.jsxs(
1690
+ chunkJ6OLBSZR_js.DropdownMenuItem,
1691
+ {
1692
+ onClick: () => column.toggleVisibility(false),
1693
+ className: "text-xs",
1694
+ children: [
1695
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: "mr-2 size-3.5 text-muted-foreground" }),
1696
+ "Hide"
1697
+ ]
1698
+ }
1699
+ )
1700
+ ] })
1701
+ ] })
1702
+ ] }) });
1703
+ }
1704
+ var FinanceDisplayContext = React3__namespace.createContext({
1705
+ decimals: 0,
1706
+ displayUnits: "actuals",
1707
+ currencySignDisplay: "all"
1708
+ });
1709
+ var FinanceDecimalsContext = React3__namespace.createContext(0);
1710
+ function FinanceDisplayProvider({
1711
+ decimals,
1712
+ displayUnits = "actuals",
1713
+ currencySignDisplay = "all",
1714
+ children
1715
+ }) {
1716
+ const value = React3__namespace.useMemo(
1717
+ () => ({ decimals, displayUnits, currencySignDisplay }),
1718
+ [decimals, displayUnits, currencySignDisplay]
1719
+ );
1720
+ return /* @__PURE__ */ jsxRuntime.jsx(FinanceDisplayContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(FinanceDecimalsContext.Provider, { value: decimals, children }) });
1721
+ }
1722
+ function FinanceDecimalsProvider({
1723
+ decimals,
1724
+ children
1725
+ }) {
1726
+ return /* @__PURE__ */ jsxRuntime.jsx(FinanceDisplayProvider, { decimals, children });
1727
+ }
1728
+ function useFinanceDecimals() {
1729
+ return React3__namespace.useContext(FinanceDecimalsContext);
1730
+ }
1731
+ function useFinanceDisplay() {
1732
+ return React3__namespace.useContext(FinanceDisplayContext);
1733
+ }
1734
+ function getUnitDivisor(units) {
1735
+ switch (units) {
1736
+ case "thousands":
1737
+ return 1e3;
1738
+ case "millions":
1739
+ return 1e6;
1740
+ default:
1741
+ return 1;
1742
+ }
1743
+ }
1744
+ function getUnitLabel(units) {
1745
+ switch (units) {
1746
+ case "thousands":
1747
+ return "in thousands";
1748
+ case "millions":
1749
+ return "in millions";
1750
+ default:
1751
+ return null;
1752
+ }
1753
+ }
1754
+ function getUnitSuffix(units) {
1755
+ switch (units) {
1756
+ case "thousands":
1757
+ return "(000s)";
1758
+ case "millions":
1759
+ return "(M)";
1760
+ default:
1761
+ return null;
1762
+ }
1763
+ }
1764
+ function useFinanceDecimalsSetting(storageKey = "finance-decimal-places", defaultValue = 0) {
1765
+ const [decimals, setDecimalsState] = React3__namespace.useState(() => {
1766
+ if (typeof window === "undefined") return defaultValue;
1767
+ const stored = localStorage.getItem(storageKey);
1768
+ return stored !== null ? Number(stored) : defaultValue;
1769
+ });
1770
+ const setDecimals = React3__namespace.useCallback(
1771
+ (v) => {
1772
+ setDecimalsState(v);
1773
+ if (typeof window !== "undefined") {
1774
+ localStorage.setItem(storageKey, String(v));
1775
+ }
1776
+ },
1777
+ [storageKey]
1778
+ );
1779
+ return [decimals, setDecimals];
1780
+ }
1781
+ var formatterCache = /* @__PURE__ */ new Map();
1782
+ function getFormatter(locale, currencyCode, decimals) {
1783
+ const key = `${locale}:${currencyCode}:${decimals}`;
1784
+ let fmt = formatterCache.get(key);
1785
+ if (!fmt) {
1786
+ fmt = new Intl.NumberFormat(locale, {
1787
+ style: "currency",
1788
+ currency: currencyCode,
1789
+ minimumFractionDigits: decimals,
1790
+ maximumFractionDigits: decimals
1791
+ });
1792
+ formatterCache.set(key, fmt);
1793
+ }
1794
+ return fmt;
1795
+ }
1796
+ function formatCurrencyValue(value, options) {
1797
+ const raw = value ?? 0;
1798
+ const divisor = getUnitDivisor(options?.displayUnits ?? "actuals");
1799
+ const v = divisor === 1 ? raw : raw / divisor;
1800
+ const isZero = raw === 0;
1801
+ const isNegative = v < 0;
1802
+ const curr = options?.currency ?? "USD";
1803
+ const locale = options?.locale ?? "en-US";
1804
+ const dashZero = options?.dashZero ?? false;
1805
+ const decimals = options?.decimals ?? 2;
1806
+ const showSign = options?.showCurrencySign ?? true;
1807
+ if (isZero && dashZero) {
1808
+ return { text: "\u2014", isNegative: false, isZero: true };
1809
+ }
1810
+ const absV = Math.abs(v);
1811
+ let formatted;
1812
+ if (showSign) {
1813
+ const fmt = getFormatter(locale, curr, decimals);
1814
+ formatted = fmt.format(absV);
1815
+ } else {
1816
+ formatted = absV.toLocaleString(locale, {
1817
+ minimumFractionDigits: decimals,
1818
+ maximumFractionDigits: decimals
1819
+ });
1820
+ }
1821
+ if (isNegative) {
1822
+ return { text: `(${formatted})`, isNegative: true, isZero: false };
1823
+ }
1824
+ return { text: formatted, isNegative: false, isZero };
1825
+ }
1826
+ function DataTableCurrencyCell({
1827
+ value,
1828
+ currency: currencyCode = "USD",
1829
+ locale = "en-US",
1830
+ dashZero = false,
1831
+ decimals,
1832
+ className,
1833
+ /** Whether this cell is in a summary/total row */
1834
+ isSummaryRow
1835
+ }) {
1836
+ const ctx = useFinanceDisplay();
1837
+ const resolvedDecimals = decimals ?? ctx.decimals;
1838
+ const showCurrencySign = ctx.currencySignDisplay === "all" || ctx.currencySignDisplay === "summary" && isSummaryRow;
1839
+ const { text, isNegative, isZero } = formatCurrencyValue(value, {
1840
+ currency: currencyCode,
1841
+ locale,
1842
+ dashZero,
1843
+ decimals: resolvedDecimals,
1844
+ displayUnits: ctx.displayUnits,
1845
+ showCurrencySign
1846
+ });
1847
+ return /* @__PURE__ */ jsxRuntime.jsx(
1848
+ "span",
1849
+ {
1850
+ className: chunkADIDI7AJ_js.cn(
1851
+ "font-mono tabular-nums",
1852
+ isNegative && "text-red-600 dark:text-red-400",
1853
+ isZero && dashZero && "text-muted-foreground",
1854
+ className
1855
+ ),
1856
+ children: text
1857
+ }
1858
+ );
1859
+ }
1860
+
1861
+ // src/blocks/data-table/financialStatementRowImportance.ts
1862
+ var DEFAULT_ROW_IMPORTANCE_CONFIG = {
1863
+ "income-statement": {
1864
+ emphasis: ["Total Revenue", "Total Expenses", "Operating Income"],
1865
+ keySummary: ["Net Income"]
1866
+ },
1867
+ "balance-sheet": {
1868
+ emphasis: ["Total Liabilities", "Total Equity"],
1869
+ keySummary: ["Total Assets", "Total Liabilities & Equity"]
1870
+ },
1871
+ "cash-flow": {
1872
+ emphasis: [
1873
+ "Total Operating Activities",
1874
+ "Total Investing Activities",
1875
+ "Total Financing Activities",
1876
+ "Net Cash from Operating Activities",
1877
+ "Net Cash from Investing Activities",
1878
+ "Net Cash from Financing Activities"
1879
+ ],
1880
+ keySummary: [
1881
+ "Net Change in Cash",
1882
+ "Ending Cash",
1883
+ "Total Cash & Cash Equivalents"
1884
+ ]
1885
+ },
1886
+ "working-capital": {
1887
+ emphasis: ["Total Current Assets", "Total Current Liabilities"],
1888
+ keySummary: ["NWC", "Net Working Capital"]
1889
+ }
1890
+ };
1891
+ function normalizeLabel(value) {
1892
+ return value.trim().toLowerCase().replace(/\s+/g, " ");
1893
+ }
1894
+ function createFinancialStatementRowImportanceResolver(kind, overrides) {
1895
+ const base = DEFAULT_ROW_IMPORTANCE_CONFIG[kind];
1896
+ const emphasis = new Set(
1897
+ (overrides?.emphasis ?? base?.emphasis ?? []).map(normalizeLabel)
1898
+ );
1899
+ const keySummary = new Set(
1900
+ (overrides?.keySummary ?? base?.keySummary ?? []).map(normalizeLabel)
1901
+ );
1902
+ return (row) => {
1903
+ const label = normalizeLabel(row.name);
1904
+ if (keySummary.has(label)) return "key-summary";
1905
+ if (emphasis.has(label)) return "emphasis";
1906
+ return "normal";
1907
+ };
1908
+ }
1909
+ function getFinancialStatementRowImportanceClassName(importance) {
1910
+ switch (importance) {
1911
+ case "emphasis":
1912
+ return "bg-muted/25 border-t border-border/50 font-medium";
1913
+ case "key-summary":
1914
+ return "bg-muted/45 border-t-2 border-border/70 font-semibold";
1915
+ default:
1916
+ return void 0;
1917
+ }
1918
+ }
1919
+ var TOLERANCE = 0.01;
1920
+ function RecCheck({ computed, raw }) {
1921
+ const diff = Math.abs(computed - raw);
1922
+ const matches = diff <= TOLERANCE;
1923
+ const icon = matches ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "size-3.5 text-white fill-emerald-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-3.5 text-white fill-amber-500" });
1924
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkSORWLKOK_js.TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkSORWLKOK_js.Tooltip, { children: [
1925
+ /* @__PURE__ */ jsxRuntime.jsx(chunkSORWLKOK_js.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: icon }) }),
1926
+ /* @__PURE__ */ jsxRuntime.jsx(chunkSORWLKOK_js.TooltipContent, { side: "left", className: "text-[11px] max-w-none p-2", children: matches ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-emerald-400", children: "\u2713 Balanced \u2014 computed total matches source data" }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1927
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-amber-400 font-medium", children: "\u26A0 Variance detected" }),
1928
+ /* @__PURE__ */ jsxRuntime.jsx("table", { className: "text-[11px]", children: /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
1929
+ /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1930
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "pr-3 text-muted-foreground", children: "Computed:" }),
1931
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "font-mono tabular-nums text-right", children: formatCurrencyValue(computed, { decimals: 2 }).text })
1932
+ ] }),
1933
+ /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1934
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "pr-3 text-muted-foreground", children: "Source:" }),
1935
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "font-mono tabular-nums text-right", children: formatCurrencyValue(raw, { decimals: 2 }).text })
1936
+ ] }),
1937
+ /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-t border-border/40", children: [
1938
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "pr-3 text-muted-foreground pt-0.5", children: "Variance:" }),
1939
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "font-mono tabular-nums text-right pt-0.5 text-amber-400", children: formatCurrencyValue(computed - raw, { decimals: 2 }).text })
1940
+ ] })
1941
+ ] }) })
1942
+ ] }) })
1943
+ ] }) });
1944
+ }
1945
+ function splitMetricFormula(formula) {
1946
+ const lines = formula.split("\n").map((line) => line.trim()).filter(Boolean);
1947
+ return {
1948
+ equationLine: lines[0] ?? formula,
1949
+ detailLines: lines.slice(1)
1950
+ };
1951
+ }
1952
+ function MetricEquationTooltip({
1953
+ title,
1954
+ formula
1955
+ }) {
1956
+ const { equationLine } = splitMetricFormula(formula);
1957
+ const [lhs, rhs] = equationLine.split("=").map((part) => part.trim());
1958
+ if (!rhs) {
1959
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs leading-relaxed", children: formula });
1960
+ }
1961
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
1962
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-medium text-muted-foreground/90", children: title }),
1963
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-slate-500/15 bg-gradient-to-r from-slate-500/[0.05] via-sky-500/[0.04] to-emerald-500/[0.05] px-2.5 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs font-mono tracking-tight leading-relaxed text-foreground/85", children: [
1964
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-sky-700/85 dark:text-sky-200/85", children: lhs }),
1965
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1 text-muted-foreground/80", children: "=" }),
1966
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-emerald-700/85 dark:text-emerald-200/85", children: rhs })
1967
+ ] }) })
1968
+ ] });
1969
+ }
1970
+ function toPeriodKey(date, unit) {
1971
+ const [y, m] = date.split("-").map(Number);
1972
+ if (unit === "year") return String(y);
1973
+ if (unit === "quarter") {
1974
+ const q = Math.floor((m - 1) / 3) + 1;
1975
+ return `${y}-Q${q}`;
1976
+ }
1977
+ return `${y}-${String(m).padStart(2, "0")}`;
1978
+ }
1979
+ function resolvePeriodColumns(periods, timeUnit, periodOrder, periodColumnOrder = "oldest-first") {
1980
+ const basePeriods = periodColumnOrder === "newest-first" ? [...periods].reverse() : periods;
1981
+ if (!periodOrder || periodOrder.length === 0) return basePeriods;
1982
+ const normalizedOrder = periodOrder.map((pk) => toPeriodKey(pk, timeUnit));
1983
+ const periodSet = new Set(basePeriods);
1984
+ const prioritized = Array.from(new Set(normalizedOrder)).filter(
1985
+ (pk) => periodSet.has(pk)
1986
+ );
1987
+ const remainder = basePeriods.filter((pk) => !prioritized.includes(pk));
1988
+ return [...prioritized, ...remainder];
1989
+ }
1990
+ function calculateDesktopFinancialColumnSizing({
1991
+ periods,
1992
+ rows,
1993
+ showRowTotals,
1994
+ showVariance
1995
+ }) {
1996
+ const MIN_ACCOUNT = 260;
1997
+ const MIN_DATA = 88;
1998
+ const MIN_TOTAL = 96;
1999
+ const VARIANCE_COL = showVariance ? 80 : 0;
2000
+ const TARGET_TABLE_WIDTH = 1180;
2001
+ let maxNumericChars = 1;
2002
+ for (const row of rows) {
2003
+ for (const pk of periods) {
2004
+ maxNumericChars = Math.max(
2005
+ maxNumericChars,
2006
+ Math.round(Math.abs(row.periodAmounts[pk] ?? 0)).toLocaleString().length
2007
+ );
2008
+ }
2009
+ maxNumericChars = Math.max(
2010
+ maxNumericChars,
2011
+ Math.round(Math.abs(row.total ?? 0)).toLocaleString().length
2012
+ );
2013
+ }
2014
+ let dataSize = Math.min(156, Math.max(104, maxNumericChars * 9 + 26));
2015
+ let totalSize = Math.max(MIN_TOTAL, dataSize + 8);
2016
+ let accountSize = Math.max(340, 620 - periods.length * 26);
2017
+ let tableWidth = accountSize + periods.length * dataSize + (showRowTotals ? totalSize : 0) + VARIANCE_COL;
2018
+ if (tableWidth > TARGET_TABLE_WIDTH) {
2019
+ const reducibleAccount = accountSize - MIN_ACCOUNT;
2020
+ const needed = tableWidth - TARGET_TABLE_WIDTH;
2021
+ const reduceAccount = Math.min(reducibleAccount, needed);
2022
+ accountSize -= reduceAccount;
2023
+ tableWidth -= reduceAccount;
2024
+ }
2025
+ if (tableWidth > TARGET_TABLE_WIDTH && periods.length > 0) {
2026
+ const reducibleDataPerCol = Math.max(0, dataSize - MIN_DATA);
2027
+ const totalReducible = reducibleDataPerCol * periods.length;
2028
+ const needed = tableWidth - TARGET_TABLE_WIDTH;
2029
+ const reduceTotal = Math.min(totalReducible, needed);
2030
+ const perCol = Math.floor(reduceTotal / periods.length);
2031
+ dataSize = Math.max(MIN_DATA, dataSize - perCol);
2032
+ if (showRowTotals) {
2033
+ totalSize = Math.max(MIN_TOTAL, totalSize - Math.ceil(perCol * 0.9));
2034
+ }
2035
+ }
2036
+ return {
2037
+ accountSize,
2038
+ accountMinSize: MIN_ACCOUNT,
2039
+ dataSize,
2040
+ dataMinSize: MIN_DATA,
2041
+ totalSize
2042
+ };
2043
+ }
2044
+ function toPeriodLabel(key, unit) {
2045
+ if (unit === "year") return key;
2046
+ if (unit === "quarter") return key.replace("-", " ");
2047
+ const [year, month] = key.split("-");
2048
+ const date = new Date(Number(year), Number(month) - 1);
2049
+ return date.toLocaleDateString("en-US", { month: "short", year: "2-digit" });
2050
+ }
2051
+ function sumChildPeriods(children) {
2052
+ const periodAmounts = {};
2053
+ let total = 0;
2054
+ for (const child of children) {
2055
+ total += child.total;
2056
+ for (const [pk, amt] of Object.entries(child.periodAmounts)) {
2057
+ periodAmounts[pk] = (periodAmounts[pk] || 0) + amt;
2058
+ }
2059
+ }
2060
+ return { periodAmounts, total };
2061
+ }
2062
+ function buildAccountTree(accounts, sign) {
2063
+ const byNumber = /* @__PURE__ */ new Map();
2064
+ for (const a of accounts) {
2065
+ if (a.number) byNumber.set(a.number, a);
2066
+ }
2067
+ const nameToNumber = /* @__PURE__ */ new Map();
2068
+ for (const a of accounts) {
2069
+ if (a.number && a.name) nameToNumber.set(a.name, a.number);
2070
+ }
2071
+ const synthetics = [];
2072
+ for (const a of accounts) {
2073
+ if (a.isSubAccount && a.parentNumber && a.parentNumber !== a.number && !byNumber.has(a.parentNumber)) {
2074
+ const parentName = a.parentName ?? a.name;
2075
+ const synthetic = {
2076
+ id: `synthetic-${a.parentNumber}`,
2077
+ name: parentName,
2078
+ secondaryLabel: null,
2079
+ number: a.parentNumber,
2080
+ type: a.type,
2081
+ subType: a.subType,
2082
+ isSubAccount: false,
2083
+ parentNumber: null,
2084
+ parentName: null,
2085
+ periods: {},
2086
+ total: 0
2087
+ };
2088
+ byNumber.set(a.parentNumber, synthetic);
2089
+ nameToNumber.set(parentName, a.parentNumber);
2090
+ synthetics.push(synthetic);
2091
+ }
2092
+ }
2093
+ for (const s of synthetics) {
2094
+ const lastColon = s.name.lastIndexOf(":");
2095
+ if (lastColon > 0) {
2096
+ const grandparentPath = s.name.substring(0, lastColon);
2097
+ const gpNumber = nameToNumber.get(grandparentPath);
2098
+ if (gpNumber && gpNumber !== s.number) {
2099
+ s.isSubAccount = true;
2100
+ s.parentNumber = gpNumber;
2101
+ s.parentName = grandparentPath;
2102
+ }
2103
+ }
2104
+ }
2105
+ for (const s of synthetics) {
2106
+ accounts.push(s);
2107
+ }
2108
+ const roots = [];
2109
+ const childrenOf = /* @__PURE__ */ new Map();
2110
+ for (const a of accounts) {
2111
+ if (a.isSubAccount && a.parentNumber && a.parentNumber !== a.number && byNumber.has(a.parentNumber)) {
2112
+ const existing = childrenOf.get(a.parentNumber) || [];
2113
+ existing.push(a);
2114
+ childrenOf.set(a.parentNumber, existing);
2115
+ } else {
2116
+ roots.push(a);
2117
+ }
2118
+ }
2119
+ function buildRow(acct, depth) {
2120
+ const kids = childrenOf.get(acct.number ?? "") || [];
2121
+ const childRows = kids.sort((a, b) => (a.number ?? "").localeCompare(b.number ?? "")).map((k) => buildRow(k, depth + 1));
2122
+ const periodAmounts = {};
2123
+ let total = 0;
2124
+ if (childRows.length > 0) {
2125
+ const childSums = sumChildPeriods(childRows);
2126
+ total = acct.total * sign + childSums.total;
2127
+ for (const pk of Object.keys({
2128
+ ...acct.periods,
2129
+ ...childSums.periodAmounts
2130
+ })) {
2131
+ periodAmounts[pk] = (acct.periods[pk] || 0) * sign + (childSums.periodAmounts[pk] || 0);
2132
+ }
2133
+ } else {
2134
+ total = acct.total * sign;
2135
+ for (const [pk, amt] of Object.entries(acct.periods)) {
2136
+ periodAmounts[pk] = amt * sign;
2137
+ }
2138
+ }
2139
+ return {
2140
+ _type: childRows.length > 0 ? "account-group" : "account",
2141
+ id: acct.id,
2142
+ name: acct.name.includes(":") ? acct.name.substring(acct.name.lastIndexOf(":") + 1) : acct.name,
2143
+ accountNumber: acct.number,
2144
+ secondaryLabel: acct.secondaryLabel,
2145
+ accountType: acct.type,
2146
+ accountSubType: acct.subType,
2147
+ periodAmounts,
2148
+ total,
2149
+ children: childRows,
2150
+ depth
2151
+ };
2152
+ }
2153
+ return roots.sort((a, b) => (a.number ?? "").localeCompare(b.number ?? "")).map((r) => buildRow(r, 0));
2154
+ }
2155
+ function applySubtotalRules(accountTree, rules, sectionId) {
2156
+ const sortedRules = [...rules].sort((a, b) => a.order - b.order);
2157
+ const compiled = sortedRules.map((r) => ({
2158
+ rule: r,
2159
+ regex: new RegExp(r.pattern)
2160
+ }));
2161
+ const groups = /* @__PURE__ */ new Map();
2162
+ const unmatched = [];
2163
+ for (const r of sortedRules) {
2164
+ groups.set(r.label, []);
2165
+ }
2166
+ function matchRow(row) {
2167
+ for (const { rule, regex } of compiled) {
2168
+ if (row.accountNumber && regex.test(row.accountNumber)) {
2169
+ return rule.label;
2170
+ }
2171
+ }
2172
+ return null;
2173
+ }
2174
+ let anyMatched = false;
2175
+ for (const row of accountTree) {
2176
+ const groupLabel = matchRow(row);
2177
+ if (groupLabel) {
2178
+ groups.get(groupLabel).push(row);
2179
+ anyMatched = true;
2180
+ } else {
2181
+ unmatched.push(row);
2182
+ }
2183
+ }
2184
+ if (!anyMatched) {
2185
+ return accountTree;
2186
+ }
2187
+ const result = [];
2188
+ for (const rule of sortedRules) {
2189
+ const groupRows = groups.get(rule.label) ?? [];
2190
+ if (groupRows.length === 0) continue;
2191
+ const sums = sumChildPeriods(groupRows);
2192
+ result.push({
2193
+ _type: "subtotal-group",
2194
+ id: `subtotal-${sectionId}-${rule.label.toLowerCase().replace(/\s+/g, "-")}`,
2195
+ name: rule.label,
2196
+ accountNumber: null,
2197
+ periodAmounts: sums.periodAmounts,
2198
+ total: sums.total,
2199
+ children: groupRows,
2200
+ depth: 0
2201
+ });
2202
+ }
2203
+ if (unmatched.length > 0) {
2204
+ const sums = sumChildPeriods(unmatched);
2205
+ result.push({
2206
+ _type: "subtotal-group",
2207
+ id: `subtotal-${sectionId}-other`,
2208
+ name: "Other",
2209
+ accountNumber: null,
2210
+ periodAmounts: sums.periodAmounts,
2211
+ total: sums.total,
2212
+ children: unmatched,
2213
+ depth: 0
2214
+ });
2215
+ }
2216
+ return result;
2217
+ }
2218
+ function filterZeroRows(rows) {
2219
+ return rows.reduce((acc, row) => {
2220
+ if (row._type === "section-header" || row._type === "section-total" || row._type === "grand-total") {
2221
+ if (row.children.length > 0) {
2222
+ acc.push({ ...row, children: filterZeroRows(row.children) });
2223
+ } else {
2224
+ acc.push(row);
2225
+ }
2226
+ return acc;
2227
+ }
2228
+ if (row.children.length > 0) {
2229
+ const filteredChildren = filterZeroRows(row.children);
2230
+ if (filteredChildren.length === 0) {
2231
+ const parentIsZero = row.total === 0 && Object.values(row.periodAmounts).every((v) => v === 0);
2232
+ if (parentIsZero) return acc;
2233
+ acc.push({ ...row, children: [] });
2234
+ return acc;
2235
+ }
2236
+ if (row._type === "subtotal-group") {
2237
+ const sums = sumChildPeriods(filteredChildren);
2238
+ acc.push({
2239
+ ...row,
2240
+ children: filteredChildren,
2241
+ periodAmounts: sums.periodAmounts,
2242
+ total: sums.total
2243
+ });
2244
+ } else {
2245
+ acc.push({ ...row, children: filteredChildren });
2246
+ }
2247
+ return acc;
2248
+ }
2249
+ const isZero = row.total === 0 && Object.values(row.periodAmounts).every((v) => v === 0);
2250
+ if (!isZero) {
2251
+ acc.push(row);
2252
+ }
2253
+ return acc;
2254
+ }, []);
2255
+ }
2256
+ function buildFinancialStatementData(data, config, timeUnit, subtotalRules, options) {
2257
+ const periodSet = /* @__PURE__ */ new Set();
2258
+ for (const entry of data) {
2259
+ periodSet.add(toPeriodKey(entry.period_first_day, timeUnit));
2260
+ }
2261
+ const periods = [...periodSet].sort();
2262
+ const sectionTotals = /* @__PURE__ */ new Map();
2263
+ const sectionRawTotals = /* @__PURE__ */ new Map();
2264
+ const rows = [];
2265
+ for (const section of config.sections) {
2266
+ const classSet = new Set(section.accountClasses);
2267
+ const sign = section.sign ?? 1;
2268
+ const accountMap = /* @__PURE__ */ new Map();
2269
+ for (const entry of data) {
2270
+ if (!classSet.has(entry.account_class)) continue;
2271
+ const pk = toPeriodKey(entry.period_first_day, timeUnit);
2272
+ if (!accountMap.has(entry.account_id)) {
2273
+ accountMap.set(entry.account_id, {
2274
+ id: entry.account_id,
2275
+ name: entry.account_name,
2276
+ secondaryLabel: entry.account_secondary_label ?? null,
2277
+ number: entry.account_number,
2278
+ type: entry.account_type ?? "",
2279
+ subType: entry.account_sub_type ?? null,
2280
+ isSubAccount: entry.is_sub_account ?? false,
2281
+ parentNumber: entry.parent_account_number ?? null,
2282
+ parentName: entry.parent_account_name ?? null,
2283
+ periods: {},
2284
+ total: 0
2285
+ });
2286
+ }
2287
+ const acct = accountMap.get(entry.account_id);
2288
+ acct.periods[pk] = (acct.periods[pk] || 0) + entry.amount;
2289
+ acct.total += entry.amount;
2290
+ }
2291
+ const rawPeriods = {};
2292
+ let rawTotal = 0;
2293
+ for (const entry of data) {
2294
+ if (!classSet.has(entry.account_class)) continue;
2295
+ const pk = toPeriodKey(entry.period_first_day, timeUnit);
2296
+ const val = entry.amount * sign;
2297
+ rawPeriods[pk] = (rawPeriods[pk] || 0) + val;
2298
+ rawTotal += val;
2299
+ }
2300
+ sectionRawTotals.set(section.id, {
2301
+ periodAmounts: rawPeriods,
2302
+ total: rawTotal
2303
+ });
2304
+ const accountList = [...accountMap.values()];
2305
+ const accountTree = buildAccountTree(accountList, sign);
2306
+ if (accountTree.length === 0 && !options?.preserveEmptySections) continue;
2307
+ const useSubtotals = subtotalRules?.enabled && subtotalRules.rules.length > 0;
2308
+ const sectionChildren = useSubtotals ? applySubtotalRules(accountTree, subtotalRules.rules, section.id) : accountTree;
2309
+ const sectionSums = sumChildPeriods(accountTree);
2310
+ sectionTotals.set(section.id, sectionSums);
2311
+ if (section.standalone) {
2312
+ const normalizeDepth = (items) => items.map((item) => ({
2313
+ ...item,
2314
+ depth: Math.max(0, item.depth - 1),
2315
+ children: normalizeDepth(item.children)
2316
+ }));
2317
+ rows.push(...normalizeDepth(sectionChildren));
2318
+ continue;
2319
+ }
2320
+ const sectionHeader = {
2321
+ _type: "section-header",
2322
+ id: `section-${section.id}`,
2323
+ name: section.label,
2324
+ accountNumber: null,
2325
+ periodAmounts: {},
2326
+ total: 0,
2327
+ children: sectionChildren,
2328
+ depth: 0
2329
+ };
2330
+ rows.push(sectionHeader);
2331
+ const rawSums = sectionRawTotals.get(section.id);
2332
+ rows.push({
2333
+ _type: "section-total",
2334
+ id: `total-${section.id}`,
2335
+ name: `Total ${section.label}`,
2336
+ accountNumber: null,
2337
+ periodAmounts: sectionSums.periodAmounts,
2338
+ total: sectionSums.total,
2339
+ children: [],
2340
+ depth: 0,
2341
+ _rawPeriodAmounts: rawSums?.periodAmounts,
2342
+ _rawTotal: rawSums?.total
2343
+ });
2344
+ }
2345
+ for (const total of config.totals) {
2346
+ const totalPeriods = {};
2347
+ let totalAmount = 0;
2348
+ const rawTotalPeriods = {};
2349
+ let rawTotalAmount = 0;
2350
+ for (const ref of total.formula) {
2351
+ const subtract = ref.startsWith("-");
2352
+ const sectionId = subtract ? ref.slice(1) : ref;
2353
+ const sums = sectionTotals.get(sectionId);
2354
+ const rawSums = sectionRawTotals.get(sectionId);
2355
+ if (!sums) continue;
2356
+ const mult = subtract ? -1 : 1;
2357
+ totalAmount += sums.total * mult;
2358
+ rawTotalAmount += (rawSums?.total ?? 0) * mult;
2359
+ for (const pk of periods) {
2360
+ totalPeriods[pk] = (totalPeriods[pk] || 0) + (sums.periodAmounts[pk] || 0) * mult;
2361
+ rawTotalPeriods[pk] = (rawTotalPeriods[pk] || 0) + (rawSums?.periodAmounts[pk] || 0) * mult;
2362
+ }
2363
+ }
2364
+ rows.push({
2365
+ _type: "grand-total",
2366
+ id: `grand-total-${total.label.toLowerCase().replace(/\s+/g, "-")}`,
2367
+ name: total.label,
2368
+ accountNumber: null,
2369
+ periodAmounts: totalPeriods,
2370
+ total: totalAmount,
2371
+ children: [],
2372
+ depth: 0,
2373
+ _rawPeriodAmounts: rawTotalPeriods,
2374
+ _rawTotal: rawTotalAmount
2375
+ });
2376
+ }
2377
+ return { rows, periods };
2378
+ }
2379
+ function buildColumns(periods, unit, rows, showAccountNumbers, renderAmountCell, showRowTotals = true, showVariance, currentPeriodCount, isMobile = false, mobileCompareEnabled = false, periodLabelsOverride, accountColumnLabel = "Account", accountColumnMenuItems) {
2380
+ const desktopSizing = calculateDesktopFinancialColumnSizing({
2381
+ periods,
2382
+ rows,
2383
+ showRowTotals,
2384
+ showVariance: Boolean(showVariance)
2385
+ });
2386
+ const compactMobileAccount = isMobile && periods.length <= 1;
2387
+ const cols = [
2388
+ {
2389
+ id: "account",
2390
+ accessorKey: "name",
2391
+ header: ({ column }) => /* @__PURE__ */ jsxRuntime.jsx(
2392
+ DataTableColumnHeader,
2393
+ {
2394
+ column,
2395
+ title: accountColumnLabel,
2396
+ customMenuItems: accountColumnMenuItems
2397
+ }
2398
+ ),
2399
+ meta: {
2400
+ displayName: accountColumnLabel,
2401
+ icon: lucideReact.BookOpen,
2402
+ allowHorizontalScroll: isMobile && mobileCompareEnabled
2403
+ },
2404
+ cell: ({ row }) => {
2405
+ const r = row.original;
2406
+ if (r._type === "section-header") {
2407
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: r.name });
2408
+ }
2409
+ if (r._type === "subtotal-group") {
2410
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: r.name });
2411
+ }
2412
+ if (r._type === "section-total" || r._type === "subtotal-total") {
2413
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: r.name });
2414
+ }
2415
+ if (r._type === "grand-total") {
2416
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold", children: r.name });
2417
+ }
2418
+ if (r._type === "account-group") {
2419
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
2420
+ showAccountNumbers && r.accountNumber && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-muted-foreground mr-1.5 text-xs", children: r.accountNumber }),
2421
+ r.name,
2422
+ !isMobile && r.secondaryLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1.5 text-[11px] font-normal text-muted-foreground", children: r.secondaryLabel })
2423
+ ] });
2424
+ }
2425
+ const isPlaceholder = r.accountSubType === "placeholder";
2426
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
2427
+ /* @__PURE__ */ jsxRuntime.jsxs(
2428
+ "span",
2429
+ {
2430
+ className: isPlaceholder ? "italic text-muted-foreground" : "",
2431
+ children: [
2432
+ showAccountNumbers && r.accountNumber && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-muted-foreground mr-1.5 text-xs", children: r.accountNumber }),
2433
+ r.name,
2434
+ !isMobile && r.secondaryLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1.5 text-[11px] font-normal text-muted-foreground", children: r.secondaryLabel })
2435
+ ]
2436
+ }
2437
+ ),
2438
+ r.accountType === "metric" && r.accountSubType && /* @__PURE__ */ jsxRuntime.jsx(chunkSORWLKOK_js.TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkSORWLKOK_js.Tooltip, { children: [
2439
+ /* @__PURE__ */ jsxRuntime.jsx(chunkSORWLKOK_js.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
2440
+ "button",
2441
+ {
2442
+ type: "button",
2443
+ className: "text-muted-foreground/70 hover:text-foreground transition-colors",
2444
+ "aria-label": `${r.name} metric details`,
2445
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "h-3.5 w-3.5" })
2446
+ }
2447
+ ) }),
2448
+ /* @__PURE__ */ jsxRuntime.jsx(chunkSORWLKOK_js.TooltipContent, { side: "top", className: "max-w-[340px] text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(
2449
+ MetricEquationTooltip,
2450
+ {
2451
+ title: r.name,
2452
+ formula: r.accountSubType
2453
+ }
2454
+ ) })
2455
+ ] }) })
2456
+ ] });
2457
+ },
2458
+ enableSorting: false,
2459
+ // Mobile: shrink account column based on how many period columns need to fit.
2460
+ // 2 periods → moderate shrink, 3+ periods → aggressive shrink
2461
+ size: isMobile ? mobileCompareEnabled || compactMobileAccount ? 180 : periods.length >= 3 ? 120 : periods.length >= 2 ? 160 : 260 : desktopSizing.accountSize,
2462
+ minSize: isMobile ? mobileCompareEnabled || compactMobileAccount ? 120 : periods.length >= 2 ? 80 : 200 : desktopSizing.accountMinSize,
2463
+ maxSize: isMobile && !(mobileCompareEnabled || compactMobileAccount) ? periods.length >= 3 ? 160 : periods.length >= 2 ? 200 : 320 : void 0
2464
+ }
2465
+ ];
2466
+ for (const pk of periods) {
2467
+ const label = periodLabelsOverride?.[pk] ?? toPeriodLabel(pk, unit);
2468
+ cols.push({
2469
+ id: `period-${pk}`,
2470
+ accessorFn: (row) => row.periodAmounts[pk] ?? 0,
2471
+ header: ({ column }) => /* @__PURE__ */ jsxRuntime.jsx(DataTableColumnHeader, { column, title: label }),
2472
+ meta: {
2473
+ displayName: label,
2474
+ icon: lucideReact.Calendar,
2475
+ align: "right"
2476
+ },
2477
+ cell: ({ row }) => {
2478
+ const r = row.original;
2479
+ const val = r.periodAmounts[pk] ?? 0;
2480
+ if (r._type === "section-header") return null;
2481
+ const isTotalRow = r._type === "section-total" || r._type === "grand-total";
2482
+ const bold = r._type === "grand-total" ? "font-bold" : r._type === "section-total" || r._type === "subtotal-total" || r._type === "account-group" || r._type === "subtotal-group" ? "font-semibold" : "";
2483
+ if (renderAmountCell) {
2484
+ const cellNode = renderAmountCell(r, pk, val);
2485
+ return /* @__PURE__ */ jsxRuntime.jsx(
2486
+ "span",
2487
+ {
2488
+ className: chunkADIDI7AJ_js.cn(
2489
+ bold,
2490
+ "inline-flex cursor-help border-b border-dotted border-muted-foreground/35 leading-none hover:border-muted-foreground/60"
2491
+ ),
2492
+ children: cellNode
2493
+ }
2494
+ );
2495
+ }
2496
+ const rawVal = isTotalRow ? r._rawPeriodAmounts?.[pk] : void 0;
2497
+ if (isTotalRow && rawVal !== void 0) {
2498
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2499
+ "span",
2500
+ {
2501
+ className: chunkADIDI7AJ_js.cn(
2502
+ bold,
2503
+ "flex items-center justify-end gap-1.5 group/rec w-full h-full"
2504
+ ),
2505
+ children: [
2506
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-0 group-hover/rec:opacity-100 transition-opacity flex-shrink-0 leading-[0]", children: /* @__PURE__ */ jsxRuntime.jsx(RecCheck, { computed: val, raw: rawVal }) }),
2507
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "leading-none", children: /* @__PURE__ */ jsxRuntime.jsx(
2508
+ DataTableCurrencyCell,
2509
+ {
2510
+ value: val,
2511
+ dashZero: true,
2512
+ isSummaryRow: r._type === "section-total" || r._type === "grand-total" || r._type === "subtotal-total"
2513
+ }
2514
+ ) })
2515
+ ]
2516
+ }
2517
+ );
2518
+ }
2519
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: bold, children: /* @__PURE__ */ jsxRuntime.jsx(
2520
+ DataTableCurrencyCell,
2521
+ {
2522
+ value: val,
2523
+ dashZero: true,
2524
+ isSummaryRow: r._type === "section-total" || r._type === "grand-total" || r._type === "subtotal-total"
2525
+ }
2526
+ ) });
2527
+ },
2528
+ enableSorting: false,
2529
+ // Mobile compare mode: data columns stay readable but can shrink/grow dynamically.
2530
+ size: isMobile ? mobileCompareEnabled ? 96 : 110 : desktopSizing.dataSize,
2531
+ minSize: isMobile ? mobileCompareEnabled ? 82 : 80 : desktopSizing.dataMinSize,
2532
+ maxSize: isMobile && mobileCompareEnabled ? 112 : void 0
2533
+ });
2534
+ }
2535
+ if (showRowTotals) {
2536
+ cols.push({
2537
+ id: "total",
2538
+ accessorFn: (row) => row.total,
2539
+ header: ({ column }) => /* @__PURE__ */ jsxRuntime.jsx(DataTableColumnHeader, { column, title: "Total" }),
2540
+ meta: {
2541
+ displayName: "Total",
2542
+ icon: lucideReact.DollarSign,
2543
+ align: "right"
2544
+ },
2545
+ cell: ({ row }) => {
2546
+ const r = row.original;
2547
+ if (r._type === "section-header") return null;
2548
+ const isTotalRow = r._type === "section-total" || r._type === "grand-total";
2549
+ const bold = r._type === "grand-total" ? "font-bold" : r._type === "section-total" || r._type === "subtotal-total" || r._type === "account-group" || r._type === "subtotal-group" ? "font-semibold" : "";
2550
+ if (renderAmountCell) {
2551
+ const cellNode = renderAmountCell(r, null, r.total);
2552
+ return /* @__PURE__ */ jsxRuntime.jsx(
2553
+ "span",
2554
+ {
2555
+ className: chunkADIDI7AJ_js.cn(
2556
+ bold,
2557
+ "inline-flex cursor-help border-b border-dotted border-muted-foreground/35 leading-none hover:border-muted-foreground/60"
2558
+ ),
2559
+ children: cellNode
2560
+ }
2561
+ );
2562
+ }
2563
+ if (isTotalRow && r._rawTotal !== void 0) {
2564
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2565
+ "span",
2566
+ {
2567
+ className: chunkADIDI7AJ_js.cn(
2568
+ bold,
2569
+ "flex items-center justify-end gap-1.5 group/rec w-full h-full"
2570
+ ),
2571
+ children: [
2572
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-0 group-hover/rec:opacity-100 transition-opacity flex-shrink-0 leading-[0]", children: /* @__PURE__ */ jsxRuntime.jsx(RecCheck, { computed: r.total, raw: r._rawTotal }) }),
2573
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "leading-none", children: /* @__PURE__ */ jsxRuntime.jsx(
2574
+ DataTableCurrencyCell,
2575
+ {
2576
+ value: r.total,
2577
+ dashZero: true,
2578
+ isSummaryRow: r._type === "section-total" || r._type === "grand-total" || r._type === "subtotal-total"
2579
+ }
2580
+ ) })
2581
+ ]
2582
+ }
2583
+ );
2584
+ }
2585
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: bold, children: /* @__PURE__ */ jsxRuntime.jsx(
2586
+ DataTableCurrencyCell,
2587
+ {
2588
+ value: r.total,
2589
+ dashZero: true,
2590
+ isSummaryRow: r._type === "section-total" || r._type === "grand-total" || r._type === "subtotal-total"
2591
+ }
2592
+ ) });
2593
+ },
2594
+ enableSorting: false,
2595
+ size: isMobile ? 130 : desktopSizing.totalSize,
2596
+ minSize: isMobile ? 100 : 96
2597
+ });
2598
+ }
2599
+ if (showVariance && currentPeriodCount && currentPeriodCount > 0) {
2600
+ const priorPeriods = periods.slice(0, periods.length - currentPeriodCount);
2601
+ const currentPeriods = periods.slice(periods.length - currentPeriodCount);
2602
+ cols.push({
2603
+ id: "variance",
2604
+ accessorFn: (row) => {
2605
+ const currentSum = currentPeriods.reduce(
2606
+ (s, pk) => s + (row.periodAmounts[pk] ?? 0),
2607
+ 0
2608
+ );
2609
+ const priorSum = priorPeriods.reduce(
2610
+ (s, pk) => s + (row.periodAmounts[pk] ?? 0),
2611
+ 0
2612
+ );
2613
+ if (priorSum === 0) return currentSum === 0 ? 0 : Infinity;
2614
+ return (currentSum - priorSum) / Math.abs(priorSum) * 100;
2615
+ },
2616
+ header: ({ column }) => /* @__PURE__ */ jsxRuntime.jsx(DataTableColumnHeader, { column, title: "\u0394%" }),
2617
+ meta: {
2618
+ displayName: "Variance %",
2619
+ icon: lucideReact.TrendingUp,
2620
+ align: "right"
2621
+ },
2622
+ cell: ({ row }) => {
2623
+ const r = row.original;
2624
+ if (r._type === "section-header") return null;
2625
+ const currentSum = currentPeriods.reduce(
2626
+ (s, pk) => s + (r.periodAmounts[pk] ?? 0),
2627
+ 0
2628
+ );
2629
+ const priorSum = priorPeriods.reduce(
2630
+ (s, pk) => s + (r.periodAmounts[pk] ?? 0),
2631
+ 0
2632
+ );
2633
+ if (priorSum === 0 && currentSum === 0)
2634
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2013" });
2635
+ if (priorSum === 0)
2636
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "n/a" });
2637
+ const pct = (currentSum - priorSum) / Math.abs(priorSum) * 100;
2638
+ const isPositive = pct > 0;
2639
+ const isNegative = pct < 0;
2640
+ const bold = r._type === "grand-total" ? "font-bold" : r._type === "section-total" || r._type === "subtotal-total" ? "font-semibold" : "";
2641
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2642
+ "span",
2643
+ {
2644
+ className: chunkADIDI7AJ_js.cn(
2645
+ bold,
2646
+ "tabular-nums text-xs",
2647
+ isPositive && "text-emerald-500",
2648
+ isNegative && "text-red-500",
2649
+ !isPositive && !isNegative && "text-muted-foreground"
2650
+ ),
2651
+ children: [
2652
+ isPositive ? "+" : "",
2653
+ pct.toFixed(1),
2654
+ "%"
2655
+ ]
2656
+ }
2657
+ );
2658
+ },
2659
+ enableSorting: false,
2660
+ size: 80,
2661
+ minSize: 60
2662
+ });
2663
+ }
2664
+ return cols;
2665
+ }
2666
+ function getRowClassName(row, rowImportanceResolver) {
2667
+ const structuralClass = (() => {
2668
+ switch (row.original._type) {
2669
+ case "section-header":
2670
+ return "bg-muted/30 border-b-0";
2671
+ case "subtotal-group":
2672
+ return "bg-muted/20";
2673
+ case "section-total":
2674
+ case "subtotal-total":
2675
+ return "bg-muted/40 border-t border-border font-semibold";
2676
+ case "grand-total":
2677
+ return "bg-muted/60 border-t-2 border-double border-border";
2678
+ default:
2679
+ return void 0;
2680
+ }
2681
+ })();
2682
+ const importanceClass = rowImportanceResolver ? getFinancialStatementRowImportanceClassName(
2683
+ rowImportanceResolver(row.original)
2684
+ ) : void 0;
2685
+ return chunkADIDI7AJ_js.cn(structuralClass, importanceClass);
2686
+ }
2687
+ function FinancialStatementTable({
2688
+ data,
2689
+ timeUnit,
2690
+ config,
2691
+ showAccountNumbers = true,
2692
+ treeIndentPx = 20,
2693
+ subtotalRules,
2694
+ hideZeroRows = false,
2695
+ preserveEmptySections = false,
2696
+ showRowTotals = true,
2697
+ showVariance = false,
2698
+ currentPeriodCount,
2699
+ toolbar,
2700
+ renderAmountCell,
2701
+ isMobile = false,
2702
+ mobileCompareEnabled = false,
2703
+ periodOrder,
2704
+ periodColumnOrder = "oldest-first",
2705
+ periodLabels,
2706
+ accountColumnLabel,
2707
+ accountColumnMenuItems,
2708
+ className,
2709
+ rowImportanceResolver
2710
+ }) {
2711
+ const [expanded, setExpanded] = React3__namespace.useState({});
2712
+ const [columnVisibility, setColumnVisibility] = React3__namespace.useState({});
2713
+ const [viewportLayout, setViewportLayout] = React3__namespace.useState("unknown");
2714
+ const { rows: rawRows, periods } = React3__namespace.useMemo(
2715
+ () => buildFinancialStatementData(data, config, timeUnit, subtotalRules, {
2716
+ preserveEmptySections
2717
+ }),
2718
+ [data, config, timeUnit, subtotalRules, preserveEmptySections]
2719
+ );
2720
+ const rows = React3__namespace.useMemo(
2721
+ () => hideZeroRows ? filterZeroRows(rawRows) : rawRows,
2722
+ [rawRows, hideZeroRows]
2723
+ );
2724
+ const orderedPeriods = React3__namespace.useMemo(
2725
+ () => resolvePeriodColumns(periods, timeUnit, periodOrder, periodColumnOrder),
2726
+ [periods, timeUnit, periodOrder, periodColumnOrder]
2727
+ );
2728
+ const effectiveShowRowTotals = isMobile && mobileCompareEnabled ? false : showRowTotals;
2729
+ const columns = React3__namespace.useMemo(
2730
+ () => buildColumns(
2731
+ orderedPeriods,
2732
+ timeUnit,
2733
+ rows,
2734
+ showAccountNumbers,
2735
+ renderAmountCell,
2736
+ effectiveShowRowTotals,
2737
+ showVariance,
2738
+ currentPeriodCount,
2739
+ isMobile,
2740
+ mobileCompareEnabled,
2741
+ periodLabels,
2742
+ accountColumnLabel,
2743
+ accountColumnMenuItems
2744
+ ),
2745
+ [
2746
+ orderedPeriods,
2747
+ timeUnit,
2748
+ rows,
2749
+ showAccountNumbers,
2750
+ renderAmountCell,
2751
+ effectiveShowRowTotals,
2752
+ showVariance,
2753
+ currentPeriodCount,
2754
+ isMobile,
2755
+ mobileCompareEnabled,
2756
+ periodLabels,
2757
+ accountColumnLabel,
2758
+ accountColumnMenuItems
2759
+ ]
2760
+ );
2761
+ React3__namespace.useEffect(() => {
2762
+ if (typeof window === "undefined") return;
2763
+ const updateViewportLayout = () => {
2764
+ setViewportLayout(
2765
+ window.innerWidth > window.innerHeight ? "landscape" : "portrait"
2766
+ );
2767
+ };
2768
+ updateViewportLayout();
2769
+ window.addEventListener("resize", updateViewportLayout);
2770
+ window.addEventListener("orientationchange", updateViewportLayout);
2771
+ return () => {
2772
+ window.removeEventListener("resize", updateViewportLayout);
2773
+ window.removeEventListener("orientationchange", updateViewportLayout);
2774
+ };
2775
+ }, []);
2776
+ React3__namespace.useEffect(() => {
2777
+ if (rows.length === 0) return;
2778
+ const toExpand = {};
2779
+ for (const row of rows) {
2780
+ if (row._type === "section-header") {
2781
+ toExpand[row.id] = true;
2782
+ for (const child of row.children) {
2783
+ if (child._type === "account-group" || child._type === "subtotal-group") {
2784
+ toExpand[child.id] = true;
2785
+ if (child._type === "subtotal-group") {
2786
+ for (const grandchild of child.children) {
2787
+ if (grandchild._type === "account-group") {
2788
+ toExpand[grandchild.id] = true;
2789
+ }
2790
+ }
2791
+ }
2792
+ }
2793
+ }
2794
+ }
2795
+ }
2796
+ setExpanded(toExpand);
2797
+ }, [rows]);
2798
+ const table = reactTable.useReactTable({
2799
+ data: rows,
2800
+ columns,
2801
+ getRowId: (row) => row.id,
2802
+ getCoreRowModel: reactTable.getCoreRowModel(),
2803
+ getSubRows: (row) => row.children.length > 0 ? row.children : void 0,
2804
+ getExpandedRowModel: reactTable.getExpandedRowModel(),
2805
+ state: { expanded, columnVisibility },
2806
+ onExpandedChange: setExpanded,
2807
+ onColumnVisibilityChange: setColumnVisibility
2808
+ });
2809
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
2810
+ toolbar && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-1 pb-1", children: toolbar }),
2811
+ /* @__PURE__ */ jsxRuntime.jsx(
2812
+ DataTable,
2813
+ {
2814
+ table,
2815
+ columns,
2816
+ enableTreeView: true,
2817
+ treeIndentPx,
2818
+ getRowClassName: ((row) => getRowClassName(row, rowImportanceResolver)),
2819
+ enableColumnResizing: true,
2820
+ enableRowDrag: false,
2821
+ rowSelectionStyle: "none",
2822
+ density: "compact",
2823
+ fontSize: "sm",
2824
+ stickyColumnIds: ["account"]
2825
+ },
2826
+ `fs-${isMobile ? "m" : "d"}-${mobileCompareEnabled ? "cmp" : "std"}-${viewportLayout}`
2827
+ )
2828
+ ] });
2829
+ }
2830
+ function flattenStatementForExport(data, config, timeUnit, subtotalRules, hideZeroRows) {
2831
+ let { rows: tree, periods } = buildFinancialStatementData(
2832
+ data,
2833
+ config,
2834
+ timeUnit,
2835
+ subtotalRules
2836
+ );
2837
+ if (hideZeroRows) tree = filterZeroRows(tree);
2838
+ const flat = [];
2839
+ function walk(rows, indent) {
2840
+ for (const row of rows) {
2841
+ const prefix = " ".repeat(indent);
2842
+ const exportRow = {
2843
+ type: row._type,
2844
+ account: `${prefix}${row.accountNumber ? `${row.accountNumber} ` : ""}${row.name}`,
2845
+ accountNumber: row.accountNumber ?? ""
2846
+ };
2847
+ for (const pk of periods) {
2848
+ exportRow[pk] = row.periodAmounts[pk] ?? 0;
2849
+ }
2850
+ exportRow.total = row.total;
2851
+ if (row._type !== "section-header" || row.children.length === 0) {
2852
+ flat.push(exportRow);
2853
+ } else {
2854
+ flat.push(exportRow);
2855
+ }
2856
+ if (row.children.length > 0) {
2857
+ walk(row.children, indent + 1);
2858
+ }
2859
+ }
2860
+ }
2861
+ walk(tree, 0);
2862
+ return { rows: flat, periodKeys: periods };
2863
+ }
2864
+ var INCOME_STATEMENT_CONFIG = {
2865
+ sections: [
2866
+ { id: "revenue", label: "Revenue", accountClasses: ["Revenue"] },
2867
+ { id: "expenses", label: "Expenses", accountClasses: ["Expense"] }
2868
+ ],
2869
+ totals: [{ label: "Net Income", formula: ["revenue", "-expenses"] }]
2870
+ };
2871
+ var BALANCE_SHEET_CONFIG = {
2872
+ sections: [
2873
+ { id: "assets", label: "Assets", accountClasses: ["Asset"] },
2874
+ { id: "liabilities", label: "Liabilities", accountClasses: ["Liability"] },
2875
+ { id: "equity", label: "Equity", accountClasses: ["Equity"] }
2876
+ ],
2877
+ totals: [
2878
+ {
2879
+ label: "Total Liabilities & Equity",
2880
+ formula: ["liabilities", "equity"]
2881
+ }
2882
+ ]
2883
+ };
2884
+
2885
+ // src/hooks/spreadsheetWorkbook.ts
2886
+ function escapeXml(value) {
2887
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
2888
+ }
2889
+ function styleId(style) {
2890
+ if (!style) return void 0;
2891
+ const map = {
2892
+ header: "Header",
2893
+ text: "Text",
2894
+ number: "Number",
2895
+ currency: "Currency",
2896
+ percent: "Percent",
2897
+ totalLabel: "TotalLabel",
2898
+ totalNumber: "TotalNumber"
2899
+ };
2900
+ return map[style];
2901
+ }
2902
+ function excelColumnName(columnIndex) {
2903
+ let n = columnIndex + 1;
2904
+ let result = "";
2905
+ while (n > 0) {
2906
+ const rem = (n - 1) % 26;
2907
+ result = String.fromCharCode(65 + rem) + result;
2908
+ n = Math.floor((n - 1) / 26);
2909
+ }
2910
+ return result;
2911
+ }
2912
+ function buildSpreadsheetWorkbookXml({
2913
+ worksheetName,
2914
+ rows
2915
+ }) {
2916
+ const xmlRows = rows.map(
2917
+ (row) => `<Row>${row.map((cell) => {
2918
+ const inferredType = cell.type ?? (typeof cell.value === "number" || cell.formula ? "Number" : "String");
2919
+ const rawValue = cell.value ?? "";
2920
+ const value = inferredType === "Number" ? Number(rawValue || 0) : escapeXml(String(rawValue));
2921
+ const style = styleId(cell.style);
2922
+ const styleAttr = style ? ` ss:StyleID="${style}"` : "";
2923
+ const formulaAttr = cell.formula ? ` ss:Formula="=${escapeXml(cell.formula)}"` : "";
2924
+ return `<Cell${styleAttr}${formulaAttr}><Data ss:Type="${inferredType}">${value}</Data></Cell>`;
2925
+ }).join("")}</Row>`
2926
+ ).join("\n");
2927
+ return `<?xml version="1.0" encoding="UTF-8"?>
2928
+ <?mso-application progid="Excel.Sheet"?>
2929
+ <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
2930
+ <Styles>
2931
+ <Style ss:ID="Header"><Font ss:Bold="1"/><Interior ss:Color="#F3F4F6" ss:Pattern="Solid"/></Style>
2932
+ <Style ss:ID="Text"><NumberFormat ss:Format="@"/></Style>
2933
+ <Style ss:ID="Number"><NumberFormat ss:Format="#,##0.00"/></Style>
2934
+ <Style ss:ID="Currency"><NumberFormat ss:Format="$#,##0.00;[Red]($#,##0.00)"/></Style>
2935
+ <Style ss:ID="Percent"><NumberFormat ss:Format="0.00%"/></Style>
2936
+ <Style ss:ID="TotalLabel"><Font ss:Bold="1"/><Interior ss:Color="#F9FAFB" ss:Pattern="Solid"/></Style>
2937
+ <Style ss:ID="TotalNumber"><Font ss:Bold="1"/><NumberFormat ss:Format="$#,##0.00;[Red]($#,##0.00)"/><Interior ss:Color="#F9FAFB" ss:Pattern="Solid"/></Style>
2938
+ </Styles>
2939
+ <Worksheet ss:Name="${escapeXml(worksheetName)}"><Table>
2940
+ ${xmlRows}
2941
+ </Table></Worksheet></Workbook>`;
2942
+ }
2943
+ function downloadExcelXml(xml, filename) {
2944
+ const blob = new Blob([xml], {
2945
+ type: "application/vnd.ms-excel;charset=utf-8;"
2946
+ });
2947
+ const url = URL.createObjectURL(blob);
2948
+ const link = document.createElement("a");
2949
+ link.href = url;
2950
+ link.download = `${filename}.xls`;
2951
+ link.click();
2952
+ URL.revokeObjectURL(url);
2953
+ }
2954
+
2955
+ exports.BALANCE_SHEET_CONFIG = BALANCE_SHEET_CONFIG;
2956
+ exports.DataTable = DataTable;
2957
+ exports.DataTableColumnFilter = DataTableColumnFilter;
2958
+ exports.DataTableColumnFilterContent = DataTableColumnFilterContent;
2959
+ exports.DataTableColumnHeader = DataTableColumnHeader;
2960
+ exports.DataTableContext = DataTableContext;
2961
+ exports.DataTableCurrencyCell = DataTableCurrencyCell;
2962
+ exports.DataTableFilterBadges = DataTableFilterBadges;
2963
+ exports.FinanceDecimalsProvider = FinanceDecimalsProvider;
2964
+ exports.FinanceDisplayProvider = FinanceDisplayProvider;
2965
+ exports.FinancialStatementTable = FinancialStatementTable;
2966
+ exports.INCOME_STATEMENT_CONFIG = INCOME_STATEMENT_CONFIG;
2967
+ exports.Popover = Popover;
2968
+ exports.PopoverAnchor = PopoverAnchor;
2969
+ exports.PopoverContent = PopoverContent;
2970
+ exports.PopoverTrigger = PopoverTrigger;
2971
+ exports.Table = Table;
2972
+ exports.TableBody = TableBody;
2973
+ exports.TableCaption = TableCaption;
2974
+ exports.TableCell = TableCell;
2975
+ exports.TableFooter = TableFooter;
2976
+ exports.TableHead = TableHead;
2977
+ exports.TableHeader = TableHeader;
2978
+ exports.TableRow = TableRow;
2979
+ exports.buildFinancialStatementData = buildFinancialStatementData;
2980
+ exports.buildSpreadsheetWorkbookXml = buildSpreadsheetWorkbookXml;
2981
+ exports.calculateDesktopFinancialColumnSizing = calculateDesktopFinancialColumnSizing;
2982
+ exports.createFinancialStatementRowImportanceResolver = createFinancialStatementRowImportanceResolver;
2983
+ exports.downloadExcelXml = downloadExcelXml;
2984
+ exports.excelColumnName = excelColumnName;
2985
+ exports.flattenStatementForExport = flattenStatementForExport;
2986
+ exports.formatCurrencyValue = formatCurrencyValue;
2987
+ exports.getFinancialStatementRowImportanceClassName = getFinancialStatementRowImportanceClassName;
2988
+ exports.getUnitDivisor = getUnitDivisor;
2989
+ exports.getUnitLabel = getUnitLabel;
2990
+ exports.getUnitSuffix = getUnitSuffix;
2991
+ exports.resolvePeriodColumns = resolvePeriodColumns;
2992
+ exports.useDataTableContext = useDataTableContext;
2993
+ exports.useFinanceDecimals = useFinanceDecimals;
2994
+ exports.useFinanceDecimalsSetting = useFinanceDecimalsSetting;
2995
+ exports.useFinanceDisplay = useFinanceDisplay;