shadcn-datagrid 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1569 @@
1
+ import { useState, useRef, useMemo, useCallback, useEffect, isValidElement, useReducer } from 'react';
2
+ import { ChevronsUpDown, ChevronUp, ChevronDown, CheckIcon, ChevronsLeft, ChevronLeft, ChevronRight, ChevronsRight, MoreHorizontal, Loader2, Download, ChevronDownIcon, Printer, FileSpreadsheet, ChevronUpIcon } from 'lucide-react';
3
+ import { Checkbox as Checkbox$1, Select as Select$1, ContextMenu as ContextMenu$1 } from 'radix-ui';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
8
+ import { Slot } from '@radix-ui/react-slot';
9
+ import { cva } from 'class-variance-authority';
10
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
11
+ import { parseISO, format } from 'date-fns';
12
+ import { renderToStaticMarkup } from 'react-dom/server';
13
+
14
+ // src/components/DataGrid/index.tsx
15
+ function cn(...inputs) {
16
+ return twMerge(clsx(inputs));
17
+ }
18
+ function Checkbox({
19
+ className,
20
+ ...props
21
+ }) {
22
+ return /* @__PURE__ */ jsx(
23
+ Checkbox$1.Root,
24
+ {
25
+ "data-slot": "checkbox",
26
+ className: cn(
27
+ "peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
28
+ className
29
+ ),
30
+ ...props,
31
+ children: /* @__PURE__ */ jsx(
32
+ Checkbox$1.Indicator,
33
+ {
34
+ "data-slot": "checkbox-indicator",
35
+ className: "grid place-content-center text-current transition-none",
36
+ children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5" })
37
+ }
38
+ )
39
+ }
40
+ );
41
+ }
42
+ function Table({ className, ...props }) {
43
+ return /* @__PURE__ */ jsx("div", { "data-slot": "table-container", className: "relative w-full overflow-x-auto", children: /* @__PURE__ */ jsx("table", { "data-slot": "table", className: cn("w-full caption-bottom text-sm", className), ...props }) });
44
+ }
45
+ function TableHeader({ className, ...props }) {
46
+ return /* @__PURE__ */ jsx("thead", { "data-slot": "table-header", className: cn("[&_tr]:border-b", className), ...props });
47
+ }
48
+ function TableBody({ className, ...props }) {
49
+ return /* @__PURE__ */ jsx(
50
+ "tbody",
51
+ {
52
+ "data-slot": "table-body",
53
+ className: cn("[&_tr:last-child]:border-0", className),
54
+ ...props
55
+ }
56
+ );
57
+ }
58
+ function TableRow({ className, ...props }) {
59
+ return /* @__PURE__ */ jsx(
60
+ "tr",
61
+ {
62
+ "data-slot": "table-row",
63
+ className: cn(
64
+ "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
65
+ className
66
+ ),
67
+ ...props
68
+ }
69
+ );
70
+ }
71
+ function TableHead({ className, ...props }) {
72
+ return /* @__PURE__ */ jsx(
73
+ "th",
74
+ {
75
+ "data-slot": "table-head",
76
+ className: cn(
77
+ "text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
78
+ className
79
+ ),
80
+ ...props
81
+ }
82
+ );
83
+ }
84
+ function TableCell({ className, ...props }) {
85
+ return /* @__PURE__ */ jsx(
86
+ "td",
87
+ {
88
+ "data-slot": "table-cell",
89
+ className: cn(
90
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
91
+ className
92
+ ),
93
+ ...props
94
+ }
95
+ );
96
+ }
97
+ function TooltipProvider({
98
+ delayDuration = 0,
99
+ ...props
100
+ }) {
101
+ return /* @__PURE__ */ jsx(
102
+ TooltipPrimitive.Provider,
103
+ {
104
+ "data-slot": "tooltip-provider",
105
+ delayDuration,
106
+ ...props
107
+ }
108
+ );
109
+ }
110
+ function Tooltip({ ...props }) {
111
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
112
+ }
113
+ function TooltipTrigger({ ...props }) {
114
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
115
+ }
116
+ function TooltipContent({
117
+ className,
118
+ sideOffset = 0,
119
+ children,
120
+ ...props
121
+ }) {
122
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
123
+ TooltipPrimitive.Content,
124
+ {
125
+ "data-slot": "tooltip-content",
126
+ sideOffset,
127
+ className: cn(
128
+ "bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
129
+ className
130
+ ),
131
+ ...props,
132
+ children: [
133
+ children,
134
+ /* @__PURE__ */ jsx(TooltipPrimitive.Arrow, { className: "bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
135
+ ]
136
+ }
137
+ ) });
138
+ }
139
+ var buttonVariants = cva(
140
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
141
+ {
142
+ variants: {
143
+ variant: {
144
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
145
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
146
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
147
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
148
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
149
+ link: "text-primary underline-offset-4 hover:underline"
150
+ },
151
+ size: {
152
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
153
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
154
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
155
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
156
+ icon: "size-9",
157
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
158
+ "icon-sm": "size-8",
159
+ "icon-lg": "size-10"
160
+ }
161
+ },
162
+ defaultVariants: {
163
+ variant: "default",
164
+ size: "default"
165
+ }
166
+ }
167
+ );
168
+ function Button({
169
+ className,
170
+ variant = "default",
171
+ size = "default",
172
+ asChild = false,
173
+ ...props
174
+ }) {
175
+ const Comp = asChild ? Slot : "button";
176
+ return /* @__PURE__ */ jsx(
177
+ Comp,
178
+ {
179
+ "data-slot": "button",
180
+ "data-variant": variant,
181
+ "data-size": size,
182
+ className: cn(buttonVariants({ variant, size, className })),
183
+ ...props
184
+ }
185
+ );
186
+ }
187
+ function DropdownMenu({ ...props }) {
188
+ return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
189
+ }
190
+ function DropdownMenuTrigger({
191
+ ...props
192
+ }) {
193
+ return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
194
+ }
195
+ function DropdownMenuContent({
196
+ className,
197
+ sideOffset = 4,
198
+ ...props
199
+ }) {
200
+ return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
201
+ DropdownMenuPrimitive.Content,
202
+ {
203
+ "data-slot": "dropdown-menu-content",
204
+ sideOffset,
205
+ className: cn(
206
+ "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 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
207
+ className
208
+ ),
209
+ ...props
210
+ }
211
+ ) });
212
+ }
213
+ function DropdownMenuItem({
214
+ className,
215
+ inset,
216
+ variant = "default",
217
+ ...props
218
+ }) {
219
+ return /* @__PURE__ */ jsx(
220
+ DropdownMenuPrimitive.Item,
221
+ {
222
+ "data-slot": "dropdown-menu-item",
223
+ "data-inset": inset,
224
+ "data-variant": variant,
225
+ className: cn(
226
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
227
+ className
228
+ ),
229
+ ...props
230
+ }
231
+ );
232
+ }
233
+ function DropdownMenuSeparator({
234
+ className,
235
+ ...props
236
+ }) {
237
+ return /* @__PURE__ */ jsx(
238
+ DropdownMenuPrimitive.Separator,
239
+ {
240
+ "data-slot": "dropdown-menu-separator",
241
+ className: cn("bg-border -mx-1 my-1 h-px", className),
242
+ ...props
243
+ }
244
+ );
245
+ }
246
+ function ActionIconButton({ action, data }) {
247
+ const isDisabled = action.disabled?.(data) ?? false;
248
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
249
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
250
+ Button,
251
+ {
252
+ variant: "ghost",
253
+ size: "icon",
254
+ disabled: isDisabled,
255
+ className: `dg-action-btn h-7 w-7 ${action.variant === "destructive" ? "hover:text-destructive" : ""}`,
256
+ onClick: (e) => {
257
+ e.stopPropagation();
258
+ action.onClick(data);
259
+ },
260
+ children: action.icon
261
+ }
262
+ ) }),
263
+ /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { children: action.label }) })
264
+ ] });
265
+ }
266
+ function DataGridActions({ config, data, isHovered = true }) {
267
+ const { mode, showOnHover, actions } = config;
268
+ const visibleActions = actions.filter((action) => !action.hidden || !action.hidden(data));
269
+ if (visibleActions.length === 0) return null;
270
+ if (mode === "dropdown") {
271
+ const shouldShow = !showOnHover || isHovered;
272
+ return /* @__PURE__ */ jsx(
273
+ "div",
274
+ {
275
+ className: "dg-actions dg-actions--dropdown flex justify-end",
276
+ style: { opacity: shouldShow ? 1 : 0, transition: "opacity 0.15s" },
277
+ children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
278
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "dg-actions__trigger h-8 w-8 p-0", children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "h-4 w-4" }) }) }),
279
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", className: "dg-actions__content", children: visibleActions.map((action, index) => {
280
+ const isDisabled = action.disabled?.(data) ?? false;
281
+ return /* @__PURE__ */ jsxs("div", { children: [
282
+ index > 0 && visibleActions[index - 1]?.variant !== action.variant && action.variant === "destructive" && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
283
+ /* @__PURE__ */ jsxs(
284
+ DropdownMenuItem,
285
+ {
286
+ disabled: isDisabled,
287
+ onClick: () => action.onClick(data),
288
+ className: action.variant === "destructive" ? "text-destructive focus:text-destructive" : "",
289
+ children: [
290
+ action.icon && /* @__PURE__ */ jsx("span", { className: "mr-2", children: action.icon }),
291
+ action.label
292
+ ]
293
+ }
294
+ )
295
+ ] }, action.label);
296
+ }) })
297
+ ] })
298
+ }
299
+ );
300
+ }
301
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx("div", { className: "dg-actions dg-actions--icons flex justify-end gap-1", children: visibleActions.map((action) => /* @__PURE__ */ jsx(ActionIconButton, { action, data }, action.label)) }) });
302
+ }
303
+ function formatCurrency(value, locale = "en-US", currency = "USD") {
304
+ const num = typeof value === "number" ? value : parseFloat(String(value));
305
+ if (Number.isNaN(num)) return "-";
306
+ return new Intl.NumberFormat(locale, {
307
+ style: "currency",
308
+ currency,
309
+ minimumFractionDigits: 2,
310
+ maximumFractionDigits: 2
311
+ }).format(num);
312
+ }
313
+ function formatNumber(value, locale = "en-US") {
314
+ const num = typeof value === "number" ? value : parseFloat(String(value));
315
+ if (Number.isNaN(num)) return "-";
316
+ return new Intl.NumberFormat(locale, {
317
+ minimumFractionDigits: 2,
318
+ maximumFractionDigits: 2
319
+ }).format(num);
320
+ }
321
+ function formatDateValue(value, dateFormat = "dd MMM yyyy") {
322
+ if (!value) return "-";
323
+ try {
324
+ const date = typeof value === "string" ? parseISO(value) : value;
325
+ return format(date, dateFormat);
326
+ } catch {
327
+ return String(value);
328
+ }
329
+ }
330
+ function formatValue(value, formatType, type) {
331
+ if (value === null || value === void 0) return "-";
332
+ if (type === "date" || formatType?.includes("MMM") || formatType?.includes("yyyy")) {
333
+ return formatDateValue(value, formatType || "dd MMM yyyy");
334
+ }
335
+ if (formatType === "C2") return formatCurrency(value);
336
+ if (formatType === "N2") return formatNumber(value);
337
+ if (type === "boolean") return value ? "Yes" : "No";
338
+ return String(value);
339
+ }
340
+ function asyncReducer(_state, action) {
341
+ switch (action.type) {
342
+ case "FETCH_START":
343
+ return { data: null, isLoading: true, error: null };
344
+ case "FETCH_SUCCESS":
345
+ return { data: action.data, isLoading: false, error: null };
346
+ case "FETCH_ERROR":
347
+ return { data: null, isLoading: false, error: action.error };
348
+ }
349
+ }
350
+ function DataGridChildRow({
351
+ parentRow,
352
+ config,
353
+ parentColSpan,
354
+ className
355
+ }) {
356
+ const [asyncState, dispatch] = useReducer(asyncReducer, {
357
+ data: null,
358
+ isLoading: false,
359
+ error: null
360
+ });
361
+ const { childColumns, getChildData, fetchChildData, childKeyField = "id" } = config;
362
+ const inlineData = getChildData?.(parentRow);
363
+ useEffect(() => {
364
+ if (!inlineData && fetchChildData) {
365
+ dispatch({ type: "FETCH_START" });
366
+ fetchChildData(parentRow).then((result) => dispatch({ type: "FETCH_SUCCESS", data: result })).catch(() => dispatch({ type: "FETCH_ERROR", error: "Failed to load child data" }));
367
+ }
368
+ }, [parentRow, fetchChildData, inlineData]);
369
+ const childData = inlineData ?? asyncState.data;
370
+ const columns = childColumns ?? [];
371
+ if (asyncState.isLoading) {
372
+ return /* @__PURE__ */ jsx(TableRow, { className: cn("dg-child-row dg-child-row--loading hover:bg-transparent", className), children: /* @__PURE__ */ jsx(TableCell, { colSpan: parentColSpan, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 py-4 px-8 text-muted-foreground", children: [
373
+ /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
374
+ /* @__PURE__ */ jsx("span", { className: "text-sm", children: "Loading..." })
375
+ ] }) }) });
376
+ }
377
+ if (asyncState.error) {
378
+ return /* @__PURE__ */ jsx(TableRow, { className: cn("dg-child-row dg-child-row--error hover:bg-transparent", className), children: /* @__PURE__ */ jsx(TableCell, { colSpan: parentColSpan, children: /* @__PURE__ */ jsx("div", { className: "py-4 px-8 text-sm text-destructive", children: asyncState.error }) }) });
379
+ }
380
+ if (!childData || childData.length === 0) {
381
+ return /* @__PURE__ */ jsx(TableRow, { className: cn("dg-child-row dg-child-row--empty hover:bg-transparent", className), children: /* @__PURE__ */ jsx(TableCell, { colSpan: parentColSpan, children: /* @__PURE__ */ jsx("div", { className: "py-4 px-8 text-sm text-muted-foreground italic", children: "No child records" }) }) });
382
+ }
383
+ return /* @__PURE__ */ jsx(TableRow, { className: cn("dg-child-row hover:bg-transparent", className), children: /* @__PURE__ */ jsx(TableCell, { colSpan: parentColSpan, className: "p-0", children: /* @__PURE__ */ jsx("div", { className: "dg-child-row__container ml-10 mr-4 my-2", children: /* @__PURE__ */ jsx("div", { className: "rounded-md border border-border/50 overflow-hidden shadow-[0_1px_3px_rgba(0,0,0,0.04)] bg-muted/30", children: /* @__PURE__ */ jsxs(Table, { className: "dg-child-row__table", children: [
384
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { className: "dg-child-row__header-row bg-muted/80 hover:bg-muted/80 border-b border-border", children: columns.map((col) => /* @__PURE__ */ jsx(
385
+ TableHead,
386
+ {
387
+ className: "dg-child-row__header-cell text-[11px] font-bold text-muted-foreground/90 uppercase tracking-wider h-8",
388
+ style: {
389
+ width: typeof col.width === "number" ? `${col.width}px` : col.width,
390
+ minWidth: col.minWidth,
391
+ maxWidth: col.maxWidth
392
+ },
393
+ children: col.headerText
394
+ },
395
+ String(col.field)
396
+ )) }) }),
397
+ /* @__PURE__ */ jsx(TableBody, { children: childData.map(
398
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
399
+ (childRow, childIndex) => /* @__PURE__ */ jsx(
400
+ TableRow,
401
+ {
402
+ className: cn("dg-child-row__row", childIndex % 2 === 1 && "bg-muted/20"),
403
+ children: columns.map((col) => {
404
+ const value = childRow[col.field];
405
+ return /* @__PURE__ */ jsx(
406
+ TableCell,
407
+ {
408
+ className: "dg-child-row__cell text-xs py-2",
409
+ style: {
410
+ width: typeof col.width === "number" ? `${col.width}px` : col.width,
411
+ minWidth: col.minWidth,
412
+ maxWidth: col.maxWidth
413
+ },
414
+ children: col.template ? col.template(childRow, childIndex) : formatValue(value, col.format, col.type)
415
+ },
416
+ String(col.field)
417
+ );
418
+ })
419
+ },
420
+ childRow[childKeyField] != null ? String(childRow[childKeyField]) : childIndex
421
+ )
422
+ ) })
423
+ ] }) }) }) }) });
424
+ }
425
+ function DataGridExpander({ isExpanded, onToggle, className }) {
426
+ const handleClick = useCallback(
427
+ (e) => {
428
+ e.stopPropagation();
429
+ onToggle();
430
+ },
431
+ [onToggle]
432
+ );
433
+ return /* @__PURE__ */ jsx(
434
+ "button",
435
+ {
436
+ type: "button",
437
+ className: cn(
438
+ "dg-expander inline-flex items-center justify-center h-6 w-6 rounded-sm hover:bg-muted transition-transform duration-200",
439
+ className
440
+ ),
441
+ onClick: handleClick,
442
+ "aria-label": isExpanded ? "Collapse row" : "Expand row",
443
+ children: /* @__PURE__ */ jsx(
444
+ ChevronRight,
445
+ {
446
+ className: cn("h-4 w-4 transition-transform duration-200", isExpanded && "rotate-90")
447
+ }
448
+ )
449
+ }
450
+ );
451
+ }
452
+ function ContextMenu({ ...props }) {
453
+ return /* @__PURE__ */ jsx(ContextMenu$1.Root, { "data-slot": "context-menu", ...props });
454
+ }
455
+ function ContextMenuTrigger({
456
+ ...props
457
+ }) {
458
+ return /* @__PURE__ */ jsx(ContextMenu$1.Trigger, { "data-slot": "context-menu-trigger", ...props });
459
+ }
460
+ function ContextMenuContent({
461
+ className,
462
+ ...props
463
+ }) {
464
+ return /* @__PURE__ */ jsx(ContextMenu$1.Portal, { children: /* @__PURE__ */ jsx(
465
+ ContextMenu$1.Content,
466
+ {
467
+ "data-slot": "context-menu-content",
468
+ className: cn(
469
+ "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 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
470
+ className
471
+ ),
472
+ ...props
473
+ }
474
+ ) });
475
+ }
476
+ function ContextMenuItem({
477
+ className,
478
+ inset,
479
+ variant = "default",
480
+ ...props
481
+ }) {
482
+ return /* @__PURE__ */ jsx(
483
+ ContextMenu$1.Item,
484
+ {
485
+ "data-slot": "context-menu-item",
486
+ "data-inset": inset,
487
+ "data-variant": variant,
488
+ className: cn(
489
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
490
+ className
491
+ ),
492
+ ...props
493
+ }
494
+ );
495
+ }
496
+ function ContextMenuLabel({
497
+ className,
498
+ inset,
499
+ ...props
500
+ }) {
501
+ return /* @__PURE__ */ jsx(
502
+ ContextMenu$1.Label,
503
+ {
504
+ "data-slot": "context-menu-label",
505
+ "data-inset": inset,
506
+ className: cn("text-foreground px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className),
507
+ ...props
508
+ }
509
+ );
510
+ }
511
+ function ContextMenuSeparator({
512
+ className,
513
+ ...props
514
+ }) {
515
+ return /* @__PURE__ */ jsx(
516
+ ContextMenu$1.Separator,
517
+ {
518
+ "data-slot": "context-menu-separator",
519
+ className: cn("bg-border -mx-1 my-1 h-px", className),
520
+ ...props
521
+ }
522
+ );
523
+ }
524
+ function DataGridContextMenu({
525
+ items,
526
+ data,
527
+ children,
528
+ className
529
+ }) {
530
+ if (items.length === 0) return /* @__PURE__ */ jsx(Fragment, { children });
531
+ const processedItems = items.map((item, index) => {
532
+ if (item.type === "separator" || item.type === "label") {
533
+ return { item, index, isVisible: true };
534
+ }
535
+ const isHidden = item.hidden?.(data) ?? false;
536
+ return { item, index, isVisible: !isHidden };
537
+ });
538
+ const visibleItems = processedItems.filter((processedItem, idx) => {
539
+ const { item, isVisible } = processedItem;
540
+ if (item.type !== "separator") return isVisible;
541
+ const hasVisibleItemsAfter = processedItems.slice(idx + 1).some((pi) => pi.item.type !== "separator" && pi.isVisible);
542
+ const hasVisibleItemsBefore = processedItems.slice(0, idx).some((pi) => pi.item.type !== "separator" && pi.isVisible);
543
+ return hasVisibleItemsAfter && hasVisibleItemsBefore;
544
+ });
545
+ return /* @__PURE__ */ jsxs(ContextMenu, { children: [
546
+ /* @__PURE__ */ jsx(ContextMenuTrigger, { asChild: true, children }),
547
+ /* @__PURE__ */ jsx(ContextMenuContent, { className: cn("dg-context-menu w-56", className), children: visibleItems.map(({ item, index }) => {
548
+ if (item.type === "separator") {
549
+ return /* @__PURE__ */ jsx(
550
+ ContextMenuSeparator,
551
+ {
552
+ className: "dg-context-menu__separator"
553
+ },
554
+ `sep-${String(index)}`
555
+ );
556
+ }
557
+ if (item.type === "label") {
558
+ return /* @__PURE__ */ jsx(ContextMenuLabel, { className: "dg-context-menu__label", children: item.label }, `label-${String(index)}`);
559
+ }
560
+ const isDisabled = item.disabled?.(data) ?? false;
561
+ return /* @__PURE__ */ jsxs(
562
+ ContextMenuItem,
563
+ {
564
+ disabled: isDisabled,
565
+ onClick: () => item.onClick(data),
566
+ className: cn(
567
+ "dg-context-menu__item",
568
+ item.variant === "destructive" && "text-destructive focus:text-destructive"
569
+ ),
570
+ children: [
571
+ item.icon && /* @__PURE__ */ jsx("span", { className: "dg-context-menu__item-icon mr-2", children: item.icon }),
572
+ item.label
573
+ ]
574
+ },
575
+ `item-${item.label}`
576
+ );
577
+ }) })
578
+ ] });
579
+ }
580
+ function Select({ ...props }) {
581
+ return /* @__PURE__ */ jsx(Select$1.Root, { "data-slot": "select", ...props });
582
+ }
583
+ function SelectValue({ ...props }) {
584
+ return /* @__PURE__ */ jsx(Select$1.Value, { "data-slot": "select-value", ...props });
585
+ }
586
+ function SelectTrigger({
587
+ className,
588
+ size = "default",
589
+ children,
590
+ ...props
591
+ }) {
592
+ return /* @__PURE__ */ jsxs(
593
+ Select$1.Trigger,
594
+ {
595
+ "data-slot": "select-trigger",
596
+ "data-size": size,
597
+ className: cn(
598
+ "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
599
+ className
600
+ ),
601
+ ...props,
602
+ children: [
603
+ children,
604
+ /* @__PURE__ */ jsx(Select$1.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4 opacity-50" }) })
605
+ ]
606
+ }
607
+ );
608
+ }
609
+ function SelectScrollUpButton({
610
+ className,
611
+ ...props
612
+ }) {
613
+ return /* @__PURE__ */ jsx(
614
+ Select$1.ScrollUpButton,
615
+ {
616
+ "data-slot": "select-scroll-up-button",
617
+ className: cn("flex cursor-default items-center justify-center py-1", className),
618
+ ...props,
619
+ children: /* @__PURE__ */ jsx(ChevronUpIcon, { className: "size-4" })
620
+ }
621
+ );
622
+ }
623
+ function SelectScrollDownButton({
624
+ className,
625
+ ...props
626
+ }) {
627
+ return /* @__PURE__ */ jsx(
628
+ Select$1.ScrollDownButton,
629
+ {
630
+ "data-slot": "select-scroll-down-button",
631
+ className: cn("flex cursor-default items-center justify-center py-1", className),
632
+ ...props,
633
+ children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4" })
634
+ }
635
+ );
636
+ }
637
+ function SelectContent({
638
+ className,
639
+ children,
640
+ position = "item-aligned",
641
+ align = "center",
642
+ ...props
643
+ }) {
644
+ return /* @__PURE__ */ jsx(Select$1.Portal, { children: /* @__PURE__ */ jsxs(
645
+ Select$1.Content,
646
+ {
647
+ "data-slot": "select-content",
648
+ className: cn(
649
+ "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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
650
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
651
+ className
652
+ ),
653
+ position,
654
+ align,
655
+ ...props,
656
+ children: [
657
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
658
+ /* @__PURE__ */ jsx(
659
+ Select$1.Viewport,
660
+ {
661
+ className: cn(
662
+ "p-1",
663
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
664
+ ),
665
+ children
666
+ }
667
+ ),
668
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
669
+ ]
670
+ }
671
+ ) });
672
+ }
673
+ function SelectItem({
674
+ className,
675
+ children,
676
+ ...props
677
+ }) {
678
+ return /* @__PURE__ */ jsxs(
679
+ Select$1.Item,
680
+ {
681
+ "data-slot": "select-item",
682
+ className: cn(
683
+ "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
684
+ className
685
+ ),
686
+ ...props,
687
+ children: [
688
+ /* @__PURE__ */ jsx(
689
+ "span",
690
+ {
691
+ "data-slot": "select-item-indicator",
692
+ className: "absolute right-2 flex size-3.5 items-center justify-center",
693
+ children: /* @__PURE__ */ jsx(Select$1.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-4" }) })
694
+ }
695
+ ),
696
+ /* @__PURE__ */ jsx(Select$1.ItemText, { children })
697
+ ]
698
+ }
699
+ );
700
+ }
701
+ function getLayout(width) {
702
+ if (width >= 600) return "full";
703
+ if (width >= 400) return "compact";
704
+ return "minimal";
705
+ }
706
+ function DataGridPagination({ config, className }) {
707
+ const {
708
+ page,
709
+ pageSize,
710
+ total,
711
+ pageSizeOptions = [5, 10, 15, 20, 25],
712
+ onPageChange,
713
+ onPageSizeChange
714
+ } = config;
715
+ const totalPages = Math.ceil(total / pageSize) || 1;
716
+ const containerRef = useRef(null);
717
+ const [layout, setLayout] = useState("full");
718
+ const updateLayout = useCallback(() => {
719
+ if (containerRef.current) {
720
+ setLayout(getLayout(containerRef.current.offsetWidth));
721
+ }
722
+ }, []);
723
+ useEffect(() => {
724
+ updateLayout();
725
+ const observer = new ResizeObserver(updateLayout);
726
+ if (containerRef.current) observer.observe(containerRef.current);
727
+ return () => observer.disconnect();
728
+ }, [updateLayout]);
729
+ return /* @__PURE__ */ jsxs(
730
+ "div",
731
+ {
732
+ ref: containerRef,
733
+ className: cn(
734
+ "dg-pagination flex flex-wrap items-center gap-4 mt-4 pb-2 px-2",
735
+ layout === "minimal" ? "justify-center" : "justify-between",
736
+ className
737
+ ),
738
+ children: [
739
+ layout !== "minimal" && /* @__PURE__ */ jsxs("div", { className: "dg-pagination__page-size flex items-center gap-2", children: [
740
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground whitespace-nowrap", children: layout === "full" ? "Rows per page:" : "Rows:" }),
741
+ /* @__PURE__ */ jsxs(
742
+ Select,
743
+ {
744
+ value: pageSize.toString(),
745
+ onValueChange: (value) => {
746
+ onPageSizeChange(Number(value));
747
+ onPageChange(1);
748
+ },
749
+ children: [
750
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "dg-pagination__page-size-trigger w-[80px] h-8", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
751
+ /* @__PURE__ */ jsx(SelectContent, { children: pageSizeOptions.map((size) => /* @__PURE__ */ jsx(SelectItem, { value: size.toString(), children: size }, size)) })
752
+ ]
753
+ }
754
+ )
755
+ ] }),
756
+ layout !== "minimal" && /* @__PURE__ */ jsx("div", { className: "dg-pagination__info flex items-center gap-2", children: /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground whitespace-nowrap", children: [
757
+ (page - 1) * pageSize + 1,
758
+ "\u2013",
759
+ Math.min(page * pageSize, total),
760
+ " of ",
761
+ total
762
+ ] }) }),
763
+ /* @__PURE__ */ jsxs("div", { className: "dg-pagination__nav flex items-center gap-1", children: [
764
+ layout === "full" && /* @__PURE__ */ jsx(
765
+ Button,
766
+ {
767
+ variant: "outline",
768
+ size: "icon",
769
+ className: "dg-pagination__btn h-8 w-8",
770
+ onClick: () => onPageChange(1),
771
+ disabled: page === 1,
772
+ children: /* @__PURE__ */ jsx(ChevronsLeft, { className: "h-4 w-4" })
773
+ }
774
+ ),
775
+ /* @__PURE__ */ jsx(
776
+ Button,
777
+ {
778
+ variant: "outline",
779
+ size: "icon",
780
+ className: "dg-pagination__btn h-8 w-8",
781
+ onClick: () => onPageChange(Math.max(page - 1, 1)),
782
+ disabled: page === 1,
783
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
784
+ }
785
+ ),
786
+ /* @__PURE__ */ jsx("span", { className: "dg-pagination__page-info text-sm px-2 whitespace-nowrap", children: layout === "full" ? `Page ${String(page)} of ${String(totalPages)}` : `${String(page)}/${String(totalPages)}` }),
787
+ /* @__PURE__ */ jsx(
788
+ Button,
789
+ {
790
+ variant: "outline",
791
+ size: "icon",
792
+ className: "dg-pagination__btn h-8 w-8",
793
+ onClick: () => onPageChange(Math.min(page + 1, totalPages)),
794
+ disabled: page === totalPages,
795
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
796
+ }
797
+ ),
798
+ layout === "full" && /* @__PURE__ */ jsx(
799
+ Button,
800
+ {
801
+ variant: "outline",
802
+ size: "icon",
803
+ className: "dg-pagination__btn h-8 w-8",
804
+ onClick: () => onPageChange(totalPages),
805
+ disabled: page === totalPages,
806
+ children: /* @__PURE__ */ jsx(ChevronsRight, { className: "h-4 w-4" })
807
+ }
808
+ )
809
+ ] })
810
+ ]
811
+ }
812
+ );
813
+ }
814
+ function Skeleton({ className, ...props }) {
815
+ return /* @__PURE__ */ jsx(
816
+ "div",
817
+ {
818
+ "data-slot": "skeleton",
819
+ className: cn("bg-accent animate-pulse rounded-md", className),
820
+ ...props
821
+ }
822
+ );
823
+ }
824
+ function DataGridSkeleton({
825
+ columns,
826
+ rowCount = 5,
827
+ showCheckbox = false,
828
+ showActions = false,
829
+ showExpander = false
830
+ }) {
831
+ const visibleColumns = columns.filter((col) => col.visible !== false);
832
+ const skeletonWidths = useMemo(
833
+ () => Array.from(
834
+ { length: rowCount },
835
+ (_, rowIdx) => visibleColumns.map((_2, colIdx) => `${((rowIdx + 1) * 37 + (colIdx + 1) * 53) % 40 + 50}%`)
836
+ ),
837
+ [rowCount, visibleColumns]
838
+ );
839
+ return /* @__PURE__ */ jsx(Fragment, { children: Array.from({ length: rowCount }).map((_, rowIndex) => /* @__PURE__ */ jsxs(
840
+ TableRow,
841
+ {
842
+ className: "dg-row dg-row--skeleton hover:bg-transparent",
843
+ children: [
844
+ showExpander && /* @__PURE__ */ jsx(TableCell, { className: "dg-cell dg-cell--expander w-[40px]", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4" }) }),
845
+ showCheckbox && /* @__PURE__ */ jsx(TableCell, { className: "dg-cell dg-cell--checkbox w-[40px]", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4" }) }),
846
+ visibleColumns.map((column, colIndex) => {
847
+ const width = typeof column.width === "number" ? `${column.width}px` : column.width;
848
+ return /* @__PURE__ */ jsx(
849
+ TableCell,
850
+ {
851
+ className: "dg-cell",
852
+ style: { width, minWidth: column.minWidth, maxWidth: column.maxWidth },
853
+ children: /* @__PURE__ */ jsx(
854
+ Skeleton,
855
+ {
856
+ className: "h-4",
857
+ style: { width: skeletonWidths[rowIndex]?.[colIndex] ?? "60%" }
858
+ }
859
+ )
860
+ },
861
+ `skeleton-cell-${String(column.field)}`
862
+ );
863
+ }),
864
+ showActions && /* @__PURE__ */ jsx(TableCell, { className: "dg-cell dg-cell--actions w-[80px]", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-6 ml-auto" }) })
865
+ ]
866
+ },
867
+ `skeleton-row-${String(rowIndex)}`
868
+ )) });
869
+ }
870
+ function stripHtml(html) {
871
+ const doc = new DOMParser().parseFromString(html, "text/html");
872
+ return doc.body.textContent?.trim() ?? "";
873
+ }
874
+ function reactNodeToText(node) {
875
+ if (node === null || node === void 0) return "";
876
+ if (typeof node === "string") return node;
877
+ if (typeof node === "number" || typeof node === "boolean") return String(node);
878
+ if (isValidElement(node)) {
879
+ try {
880
+ return stripHtml(renderToStaticMarkup(node));
881
+ } catch {
882
+ return "";
883
+ }
884
+ }
885
+ return String(node);
886
+ }
887
+ function getCellExportValue(row, col, rowIndex) {
888
+ if (col.exportFormatter) return col.exportFormatter(row);
889
+ if (col.template) {
890
+ const rendered = col.template(row, rowIndex);
891
+ return reactNodeToText(rendered);
892
+ }
893
+ const value = row[col.field];
894
+ return String(formatValue(value, col.format, col.type));
895
+ }
896
+ function exportToCsv(data, columns, fileName) {
897
+ const visibleColumns = columns.filter((col) => col.visible !== false);
898
+ const headerRow = visibleColumns.map((col) => `"${col.headerText}"`).join(",");
899
+ const dataRows = data.map(
900
+ (row, rowIndex) => visibleColumns.map((col) => {
901
+ const formatted = getCellExportValue(row, col, rowIndex);
902
+ return `"${formatted.replace(/"/g, '""')}"`;
903
+ }).join(",")
904
+ );
905
+ const csv = [headerRow, ...dataRows].join("\n");
906
+ const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
907
+ const url = URL.createObjectURL(blob);
908
+ const link = document.createElement("a");
909
+ link.href = url;
910
+ link.download = `${fileName}.csv`;
911
+ link.click();
912
+ URL.revokeObjectURL(url);
913
+ }
914
+ function exportToPrint(data, columns) {
915
+ const visibleColumns = columns.filter((col) => col.visible !== false);
916
+ const tableHtml = `
917
+ <!DOCTYPE html>
918
+ <html>
919
+ <head>
920
+ <title>Print</title>
921
+ <style>
922
+ body { font-family: Inter, Arial, sans-serif; padding: 20px; }
923
+ table { border-collapse: collapse; width: 100%; font-size: 12px; }
924
+ th, td { border: 1px solid #ddd; padding: 8px 12px; text-align: left; }
925
+ th { background-color: #f5f5f5; font-weight: 600; }
926
+ tr:nth-child(even) { background-color: #fafafa; }
927
+ @media print {
928
+ body { padding: 0; }
929
+ th { background-color: #f5f5f5 !important; -webkit-print-color-adjust: exact; }
930
+ }
931
+ </style>
932
+ </head>
933
+ <body>
934
+ <table>
935
+ <thead>
936
+ <tr>${visibleColumns.map((col) => `<th>${col.headerText}</th>`).join("")}</tr>
937
+ </thead>
938
+ <tbody>
939
+ ${data.map(
940
+ (row, rowIndex) => `
941
+ <tr>
942
+ ${visibleColumns.map((col) => `<td>${getCellExportValue(row, col, rowIndex)}</td>`).join("")}
943
+ </tr>
944
+ `
945
+ ).join("")}
946
+ </tbody>
947
+ </table>
948
+ </body>
949
+ </html>
950
+ `;
951
+ const iframe = document.createElement("iframe");
952
+ iframe.style.cssText = "position:fixed;width:0;height:0;border:none;opacity:0";
953
+ document.body.appendChild(iframe);
954
+ const iframeDoc = iframe.contentDocument ?? iframe.contentWindow?.document;
955
+ if (!iframeDoc) {
956
+ document.body.removeChild(iframe);
957
+ return;
958
+ }
959
+ iframeDoc.open();
960
+ iframeDoc.write(tableHtml);
961
+ iframeDoc.close();
962
+ iframe.onload = () => {
963
+ iframe.contentWindow?.print();
964
+ setTimeout(() => document.body.removeChild(iframe), 1e3);
965
+ };
966
+ }
967
+ function getExportIcon(format) {
968
+ switch (format) {
969
+ case "csv":
970
+ return /* @__PURE__ */ jsx(FileSpreadsheet, { className: "h-4 w-4" });
971
+ case "print":
972
+ return /* @__PURE__ */ jsx(Printer, { className: "h-4 w-4" });
973
+ default:
974
+ return /* @__PURE__ */ jsx(Download, { className: "h-4 w-4" });
975
+ }
976
+ }
977
+ function getExportLabel(format) {
978
+ switch (format) {
979
+ case "csv":
980
+ return "Export as CSV";
981
+ case "print":
982
+ return "Print";
983
+ default:
984
+ return `Export as ${format.toUpperCase()}`;
985
+ }
986
+ }
987
+ function DataGridExport({
988
+ config,
989
+ data,
990
+ columns,
991
+ className
992
+ }) {
993
+ const { formats = ["csv", "print"], fileName = "export" } = config;
994
+ const handleExport = useCallback(
995
+ (format) => {
996
+ switch (format) {
997
+ case "csv":
998
+ exportToCsv(data, columns, fileName);
999
+ break;
1000
+ case "print":
1001
+ exportToPrint(data, columns);
1002
+ break;
1003
+ default:
1004
+ config.onCustomExport?.(format, data, columns);
1005
+ break;
1006
+ }
1007
+ },
1008
+ [data, columns, fileName, config]
1009
+ );
1010
+ if (formats.length === 1) {
1011
+ const format = formats[0];
1012
+ return /* @__PURE__ */ jsxs(
1013
+ Button,
1014
+ {
1015
+ variant: "outline",
1016
+ size: "sm",
1017
+ className: cn("dg-export__btn gap-2", className),
1018
+ onClick: () => handleExport(format),
1019
+ children: [
1020
+ getExportIcon(format),
1021
+ getExportLabel(format)
1022
+ ]
1023
+ }
1024
+ );
1025
+ }
1026
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1027
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: cn("dg-export__btn gap-2", className), children: [
1028
+ /* @__PURE__ */ jsx(Download, { className: "h-4 w-4" }),
1029
+ "Export"
1030
+ ] }) }),
1031
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", className: "dg-export__content", children: formats.map((format) => /* @__PURE__ */ jsxs(
1032
+ DropdownMenuItem,
1033
+ {
1034
+ onClick: () => handleExport(format),
1035
+ className: "dg-export__item gap-2",
1036
+ children: [
1037
+ getExportIcon(format),
1038
+ getExportLabel(format)
1039
+ ]
1040
+ },
1041
+ format
1042
+ )) })
1043
+ ] });
1044
+ }
1045
+ function DataGridToolbar({
1046
+ showExport,
1047
+ showBulkActions,
1048
+ selectedCount,
1049
+ bulkActionConfig,
1050
+ exportConfig,
1051
+ data,
1052
+ columns,
1053
+ getSelectedData,
1054
+ classNames = {}
1055
+ }) {
1056
+ if (!showExport && !(showBulkActions && selectedCount > 0)) return null;
1057
+ return /* @__PURE__ */ jsxs("div", { className: cn("dg-toolbar flex items-center justify-between gap-2", classNames.toolbar), children: [
1058
+ showBulkActions && selectedCount > 0 && bulkActionConfig && /* @__PURE__ */ jsxs("div", { className: "dg-toolbar__bulk flex items-center gap-2 p-2 bg-muted/50 rounded-md flex-1", children: [
1059
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1060
+ selectedCount,
1061
+ " item(s) selected"
1062
+ ] }),
1063
+ /* @__PURE__ */ jsx("div", { className: "flex gap-2 ml-auto", children: bulkActionConfig.actions.map((action) => /* @__PURE__ */ jsxs(
1064
+ "button",
1065
+ {
1066
+ type: "button",
1067
+ className: cn(
1068
+ "dg-toolbar__bulk-btn inline-flex items-center gap-1 px-3 py-1.5 text-sm rounded-md transition-colors",
1069
+ action.variant === "destructive" ? "bg-destructive text-destructive-foreground hover:bg-destructive/90" : "bg-primary text-primary-foreground hover:bg-primary/90"
1070
+ ),
1071
+ onClick: () => action.onClick(getSelectedData()),
1072
+ children: [
1073
+ action.icon,
1074
+ action.label
1075
+ ]
1076
+ },
1077
+ action.label
1078
+ )) })
1079
+ ] }),
1080
+ showExport && exportConfig && /* @__PURE__ */ jsx("div", { className: cn("dg-toolbar__export ml-auto", classNames.exportToolbar), children: /* @__PURE__ */ jsx(DataGridExport, { config: exportConfig, data, columns }) })
1081
+ ] });
1082
+ }
1083
+ function getTextAlign(align) {
1084
+ switch (align) {
1085
+ case "Right":
1086
+ return "right";
1087
+ case "Center":
1088
+ return "center";
1089
+ default:
1090
+ return "left";
1091
+ }
1092
+ }
1093
+ function getJustifyContent(align) {
1094
+ switch (align) {
1095
+ case "Right":
1096
+ return "flex-end";
1097
+ case "Center":
1098
+ return "center";
1099
+ default:
1100
+ return "flex-start";
1101
+ }
1102
+ }
1103
+ function DataGridCellContentInner({
1104
+ row,
1105
+ column,
1106
+ children
1107
+ }) {
1108
+ const tooltipCfg = column.tooltip;
1109
+ if (!tooltipCfg || tooltipCfg === true) {
1110
+ return /* @__PURE__ */ jsx("span", { className: "block truncate", children });
1111
+ }
1112
+ const config = tooltipCfg;
1113
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
1114
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "block truncate", children }) }),
1115
+ /* @__PURE__ */ jsx(TooltipContent, { side: config.side ?? "top", className: config.className, children: config.content ? config.content(row) : children })
1116
+ ] });
1117
+ }
1118
+ function DataGrid({
1119
+ columns,
1120
+ data,
1121
+ isLoading = false,
1122
+ skeletonRowCount = 5,
1123
+ pagination,
1124
+ actionConfig,
1125
+ bulkActionConfig,
1126
+ contextMenuItems,
1127
+ exportConfig,
1128
+ childRowConfig,
1129
+ emptyMessage = "No data found",
1130
+ emptyComponent,
1131
+ onRowClick,
1132
+ className,
1133
+ classNames = {},
1134
+ keyField = "id",
1135
+ sortConfig: externalSortConfig,
1136
+ onSort,
1137
+ tableContainerRef: externalContainerRef,
1138
+ stickyHeader = false,
1139
+ rowHeight,
1140
+ maxBodyHeight,
1141
+ alternatingRows = true,
1142
+ enableColumnResize = false,
1143
+ showHeaderBorder = false
1144
+ }) {
1145
+ const [internalSortConfig, setInternalSortConfig] = useState({
1146
+ field: "",
1147
+ direction: null
1148
+ });
1149
+ const sortConfig = externalSortConfig ?? internalSortConfig;
1150
+ const [selectedRows, setSelectedRows] = useState(/* @__PURE__ */ new Set());
1151
+ const [hoveredRow, setHoveredRow] = useState(null);
1152
+ const [expandedRows, setExpandedRows] = useState(/* @__PURE__ */ new Set());
1153
+ const [columnWidths, setColumnWidths] = useState({});
1154
+ const [resizingColumn, setResizingColumn] = useState(null);
1155
+ const resizeStartX = useRef(0);
1156
+ const resizeStartWidth = useRef(0);
1157
+ const justResized = useRef(false);
1158
+ const internalContainerRef = useRef(null);
1159
+ const tableContainerRef = externalContainerRef ?? internalContainerRef;
1160
+ const sortedData = useMemo(() => {
1161
+ if (onSort || !sortConfig.field || !sortConfig.direction) return data;
1162
+ return [...data].sort((a, b) => {
1163
+ const field = sortConfig.field;
1164
+ const aVal = a[field];
1165
+ const bVal = b[field];
1166
+ if (aVal == null || bVal == null) return 0;
1167
+ let cmp = 0;
1168
+ if (aVal < bVal) cmp = -1;
1169
+ else if (aVal > bVal) cmp = 1;
1170
+ return sortConfig.direction === "desc" ? -cmp : cmp;
1171
+ });
1172
+ }, [data, sortConfig, onSort]);
1173
+ const visibleColumns = useMemo(() => columns.filter((col) => col.visible !== false), [columns]);
1174
+ const showBulkActions = bulkActionConfig?.enabled ?? false;
1175
+ const showActionColumn = !!actionConfig && actionConfig.actions.length > 0;
1176
+ const showExpanderColumn = childRowConfig?.enabled ?? false;
1177
+ const showContextMenu = !!contextMenuItems && contextMenuItems.length > 0;
1178
+ const showExport = exportConfig?.enabled ?? false;
1179
+ const totalColSpan = visibleColumns.length + (showBulkActions ? 1 : 0) + (showActionColumn ? 1 : 0) + (showExpanderColumn ? 1 : 0);
1180
+ const columnsToRender = visibleColumns.map((column, index) => ({ column, index }));
1181
+ const handleSort = useCallback(
1182
+ (field, allowSorting) => {
1183
+ if (allowSorting === false) return;
1184
+ setExpandedRows(/* @__PURE__ */ new Set());
1185
+ let nextSortConfig;
1186
+ if (sortConfig.field !== field) {
1187
+ nextSortConfig = { field, direction: "asc" };
1188
+ } else if (sortConfig.direction === "asc") {
1189
+ nextSortConfig = { field, direction: "desc" };
1190
+ } else {
1191
+ nextSortConfig = { field: "", direction: null };
1192
+ }
1193
+ if (onSort) {
1194
+ if (!nextSortConfig.field || !nextSortConfig.direction) {
1195
+ onSort(null);
1196
+ } else {
1197
+ const ordering = nextSortConfig.direction === "desc" ? `-${nextSortConfig.field}` : nextSortConfig.field;
1198
+ onSort(ordering);
1199
+ }
1200
+ } else {
1201
+ setInternalSortConfig(nextSortConfig);
1202
+ }
1203
+ },
1204
+ [sortConfig, onSort]
1205
+ );
1206
+ const handleSelectAll = useCallback(() => {
1207
+ if (selectedRows.size === data.length) {
1208
+ setSelectedRows(/* @__PURE__ */ new Set());
1209
+ } else {
1210
+ const allKeys = data.map((row) => row[keyField]);
1211
+ setSelectedRows(new Set(allKeys));
1212
+ }
1213
+ }, [data, keyField, selectedRows.size]);
1214
+ const handleSelectRow = useCallback((key) => {
1215
+ setSelectedRows((prev) => {
1216
+ const next = new Set(prev);
1217
+ if (next.has(key)) next.delete(key);
1218
+ else next.add(key);
1219
+ return next;
1220
+ });
1221
+ }, []);
1222
+ const handleToggleExpand = useCallback((key) => {
1223
+ setExpandedRows((prev) => {
1224
+ const next = new Set(prev);
1225
+ if (next.has(key)) next.delete(key);
1226
+ else next.add(key);
1227
+ return next;
1228
+ });
1229
+ }, []);
1230
+ const getSelectedData = useCallback(
1231
+ () => data.filter((row) => selectedRows.has(row[keyField])),
1232
+ [data, keyField, selectedRows]
1233
+ );
1234
+ const getColumnWidth = useCallback(
1235
+ (column) => {
1236
+ const field = String(column.field);
1237
+ if (columnWidths[field] !== void 0) return columnWidths[field];
1238
+ if (typeof column.width === "number") return column.width;
1239
+ if (typeof column.width === "string") {
1240
+ const parsed = parseInt(column.width, 10);
1241
+ return isNaN(parsed) ? 150 : parsed;
1242
+ }
1243
+ return 150;
1244
+ },
1245
+ [columnWidths]
1246
+ );
1247
+ const handleResizeStart = useCallback(
1248
+ (e, column) => {
1249
+ e.preventDefault();
1250
+ e.stopPropagation();
1251
+ const field = String(column.field);
1252
+ const currentWidth = getColumnWidth(column);
1253
+ resizeStartX.current = e.clientX;
1254
+ resizeStartWidth.current = currentWidth;
1255
+ setResizingColumn(field);
1256
+ const handleMouseMove = (moveEvent) => {
1257
+ const diff = moveEvent.clientX - resizeStartX.current;
1258
+ const minW = column.minWidth ?? 20;
1259
+ const newWidth = Math.max(minW, resizeStartWidth.current + diff);
1260
+ setColumnWidths((prev) => ({ ...prev, [field]: newWidth }));
1261
+ };
1262
+ const handleMouseUp = () => {
1263
+ setResizingColumn(null);
1264
+ justResized.current = true;
1265
+ requestAnimationFrame(() => {
1266
+ justResized.current = false;
1267
+ });
1268
+ document.removeEventListener("mousemove", handleMouseMove);
1269
+ document.removeEventListener("mouseup", handleMouseUp);
1270
+ };
1271
+ document.addEventListener("mousemove", handleMouseMove);
1272
+ document.addEventListener("mouseup", handleMouseUp);
1273
+ },
1274
+ [getColumnWidth]
1275
+ );
1276
+ useEffect(() => {
1277
+ const root = document.documentElement;
1278
+ if (resizingColumn) root.classList.add("dg-resizing");
1279
+ else root.classList.remove("dg-resizing");
1280
+ return () => root.classList.remove("dg-resizing");
1281
+ }, [resizingColumn]);
1282
+ const getColumnWidthStr = (column) => {
1283
+ if (enableColumnResize) return `${getColumnWidth(column)}px`;
1284
+ if (typeof column.width === "number") return `${column.width}px`;
1285
+ if (typeof column.width === "string") return column.width;
1286
+ return void 0;
1287
+ };
1288
+ const renderSortIcon = (column) => {
1289
+ if (column.allowSorting === false) return null;
1290
+ const field = String(column.field);
1291
+ if (sortConfig.field !== field) {
1292
+ return /* @__PURE__ */ jsx(ChevronsUpDown, { className: "dg-sort-icon ml-1 h-3.5 w-3.5 opacity-30", strokeWidth: 2.5 });
1293
+ }
1294
+ if (sortConfig.direction === "asc") {
1295
+ return /* @__PURE__ */ jsx(ChevronUp, { className: "dg-sort-icon ml-1 h-3.5 w-3.5 text-primary", strokeWidth: 2.5 });
1296
+ }
1297
+ if (sortConfig.direction === "desc") {
1298
+ return /* @__PURE__ */ jsx(ChevronDown, { className: "dg-sort-icon ml-1 h-3.5 w-3.5 text-primary", strokeWidth: 2.5 });
1299
+ }
1300
+ return /* @__PURE__ */ jsx(ChevronsUpDown, { className: "dg-sort-icon ml-1 h-3.5 w-3.5 opacity-30", strokeWidth: 2.5 });
1301
+ };
1302
+ const renderCellValue = (row, column, rowIndex) => {
1303
+ if (column.template) return column.template(row, rowIndex);
1304
+ const value = row[column.field];
1305
+ const formatted = formatValue(value, column.format, column.type);
1306
+ return /* @__PURE__ */ jsx(DataGridCellContentInner, { row, column, children: formatted });
1307
+ };
1308
+ const renderRow = (row, rowIndex) => {
1309
+ const rowKey = row[keyField] ?? rowIndex;
1310
+ const isSelected = selectedRows.has(rowKey);
1311
+ const isHovered = hoveredRow === rowKey;
1312
+ const isExpanded = expandedRows.has(rowKey);
1313
+ const tableRowElement = /* @__PURE__ */ jsxs(
1314
+ TableRow,
1315
+ {
1316
+ className: cn(
1317
+ "dg-row transition-colors",
1318
+ isSelected && "dg-row--selected bg-muted",
1319
+ isExpanded && "dg-row--expanded",
1320
+ onRowClick && "cursor-pointer",
1321
+ classNames.row,
1322
+ isSelected && classNames.rowSelected,
1323
+ isExpanded && classNames.rowExpanded
1324
+ ),
1325
+ "data-state": isSelected ? "selected" : void 0,
1326
+ onClick: () => onRowClick?.(row),
1327
+ onMouseEnter: () => setHoveredRow(rowKey),
1328
+ onMouseLeave: () => setHoveredRow(null),
1329
+ style: rowHeight ? { height: rowHeight } : void 0,
1330
+ children: [
1331
+ showExpanderColumn && /* @__PURE__ */ jsx(TableCell, { className: cn("dg-cell dg-cell--expander w-[40px]", classNames.cellExpander), children: /* @__PURE__ */ jsx(DataGridExpander, { isExpanded, onToggle: () => handleToggleExpand(rowKey) }) }),
1332
+ showBulkActions && /* @__PURE__ */ jsx(TableCell, { className: cn("dg-cell dg-cell--checkbox w-[40px]", classNames.cellCheckbox), children: /* @__PURE__ */ jsx(
1333
+ Checkbox,
1334
+ {
1335
+ checked: isSelected,
1336
+ onCheckedChange: () => handleSelectRow(rowKey),
1337
+ onClick: (e) => e.stopPropagation(),
1338
+ "aria-label": `Select row ${rowIndex + 1}`
1339
+ }
1340
+ ) }),
1341
+ columnsToRender.map(({ column, index: colIndex }) => {
1342
+ const widthStr = getColumnWidthStr(column);
1343
+ return /* @__PURE__ */ jsx(
1344
+ TableCell,
1345
+ {
1346
+ className: cn("dg-cell", column.className, classNames.cell),
1347
+ style: {
1348
+ width: widthStr,
1349
+ minWidth: column.minWidth,
1350
+ maxWidth: column.maxWidth,
1351
+ textAlign: getTextAlign(column.textAlign)
1352
+ },
1353
+ "data-column": String(column.field),
1354
+ "data-col-index": colIndex,
1355
+ children: renderCellValue(row, column, rowIndex)
1356
+ },
1357
+ String(column.field)
1358
+ );
1359
+ }),
1360
+ showActionColumn && actionConfig && /* @__PURE__ */ jsx(
1361
+ TableCell,
1362
+ {
1363
+ className: cn("dg-cell dg-cell--actions", classNames.cellActions),
1364
+ style: { width: actionConfig.width || 80 },
1365
+ onClick: (e) => e.stopPropagation(),
1366
+ children: /* @__PURE__ */ jsx(DataGridActions, { config: actionConfig, data: row, isHovered })
1367
+ }
1368
+ )
1369
+ ]
1370
+ },
1371
+ rowKey
1372
+ );
1373
+ const wrappedRow = showContextMenu && contextMenuItems ? /* @__PURE__ */ jsx(
1374
+ DataGridContextMenu,
1375
+ {
1376
+ items: contextMenuItems,
1377
+ data: row,
1378
+ className: classNames.contextMenu,
1379
+ children: tableRowElement
1380
+ },
1381
+ rowKey
1382
+ ) : tableRowElement;
1383
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1384
+ wrappedRow,
1385
+ showExpanderColumn && isExpanded && childRowConfig && /* @__PURE__ */ jsx(
1386
+ DataGridChildRow,
1387
+ {
1388
+ parentRow: row,
1389
+ config: childRowConfig,
1390
+ parentColSpan: totalColSpan,
1391
+ className: classNames.childRow
1392
+ }
1393
+ )
1394
+ ] });
1395
+ };
1396
+ return /* @__PURE__ */ jsxs(
1397
+ "div",
1398
+ {
1399
+ className: cn(
1400
+ "dg-root h-full flex flex-col gap-4 w-full min-w-0 overflow-hidden",
1401
+ classNames.root,
1402
+ className
1403
+ ),
1404
+ children: [
1405
+ /* @__PURE__ */ jsx(
1406
+ DataGridToolbar,
1407
+ {
1408
+ showExport,
1409
+ showBulkActions,
1410
+ selectedCount: selectedRows.size,
1411
+ bulkActionConfig,
1412
+ exportConfig,
1413
+ data,
1414
+ columns,
1415
+ getSelectedData,
1416
+ classNames
1417
+ }
1418
+ ),
1419
+ /* @__PURE__ */ jsx(
1420
+ "div",
1421
+ {
1422
+ ref: tableContainerRef,
1423
+ className: cn(
1424
+ "dg-table-container custom-scrollbar relative overflow-auto rounded-md border flex-1 min-h-0 [&_[data-slot=table-container]]:overflow-visible",
1425
+ classNames.tableContainer
1426
+ ),
1427
+ style: {
1428
+ width: 0,
1429
+ minWidth: "100%",
1430
+ ...maxBodyHeight ? { maxHeight: maxBodyHeight } : {}
1431
+ },
1432
+ children: /* @__PURE__ */ jsxs(Table, { className: cn("dg-table", classNames.table), children: [
1433
+ /* @__PURE__ */ jsx(
1434
+ TableHeader,
1435
+ {
1436
+ className: cn(
1437
+ "dg-header",
1438
+ stickyHeader && "sticky top-0 z-10 bg-background",
1439
+ classNames.header
1440
+ ),
1441
+ children: /* @__PURE__ */ jsxs(
1442
+ TableRow,
1443
+ {
1444
+ className: cn(
1445
+ "dg-header-row bg-muted/50",
1446
+ showHeaderBorder && "dg-header-bordered",
1447
+ classNames.headerRow
1448
+ ),
1449
+ children: [
1450
+ showExpanderColumn && /* @__PURE__ */ jsx(TableHead, { className: "dg-header-cell dg-header-cell--expander w-[40px]" }),
1451
+ showBulkActions && /* @__PURE__ */ jsx(TableHead, { className: "dg-header-cell dg-header-cell--checkbox w-[40px]", children: /* @__PURE__ */ jsx(
1452
+ Checkbox,
1453
+ {
1454
+ checked: data.length > 0 && selectedRows.size === data.length,
1455
+ onCheckedChange: handleSelectAll,
1456
+ "aria-label": "Select all"
1457
+ }
1458
+ ) }),
1459
+ columnsToRender.map(({ column }) => {
1460
+ const widthStr = getColumnWidthStr(column);
1461
+ const canResize = enableColumnResize && column.allowResizing !== false;
1462
+ return /* @__PURE__ */ jsxs(
1463
+ TableHead,
1464
+ {
1465
+ className: cn(
1466
+ "dg-header-cell select-none",
1467
+ column.headerClassName,
1468
+ classNames.headerCell
1469
+ ),
1470
+ style: {
1471
+ width: widthStr,
1472
+ minWidth: column.minWidth,
1473
+ maxWidth: column.maxWidth,
1474
+ textAlign: getTextAlign(column.textAlign)
1475
+ },
1476
+ "data-column": String(column.field),
1477
+ children: [
1478
+ column.headerTemplate ? column.headerTemplate() : /* @__PURE__ */ jsxs(
1479
+ "div",
1480
+ {
1481
+ className: cn(
1482
+ "flex items-center",
1483
+ column.allowSorting !== false && "cursor-pointer"
1484
+ ),
1485
+ style: { justifyContent: getJustifyContent(column.textAlign) },
1486
+ role: "button",
1487
+ tabIndex: 0,
1488
+ onClick: () => handleSort(String(column.field), column.allowSorting),
1489
+ onKeyDown: (e) => {
1490
+ if (e.key === "Enter" || e.key === " ") {
1491
+ e.preventDefault();
1492
+ handleSort(String(column.field), column.allowSorting);
1493
+ }
1494
+ },
1495
+ children: [
1496
+ column.headerText,
1497
+ renderSortIcon(column)
1498
+ ]
1499
+ }
1500
+ ),
1501
+ canResize && /* @__PURE__ */ jsx(
1502
+ "div",
1503
+ {
1504
+ className: cn(
1505
+ "dg-resize-handle",
1506
+ resizingColumn === String(column.field) && "dg-resize-handle--active"
1507
+ ),
1508
+ onMouseDown: (e) => handleResizeStart(e, column),
1509
+ role: "separator",
1510
+ "aria-orientation": "vertical"
1511
+ }
1512
+ )
1513
+ ]
1514
+ },
1515
+ String(column.field)
1516
+ );
1517
+ }),
1518
+ showActionColumn && actionConfig && /* @__PURE__ */ jsx(
1519
+ TableHead,
1520
+ {
1521
+ className: "dg-header-cell dg-header-cell--actions text-right",
1522
+ style: { width: actionConfig.width || 80 },
1523
+ children: actionConfig.showHeader !== false ? actionConfig.headerText || "Actions" : ""
1524
+ }
1525
+ )
1526
+ ]
1527
+ }
1528
+ )
1529
+ }
1530
+ ),
1531
+ /* @__PURE__ */ jsxs(
1532
+ TableBody,
1533
+ {
1534
+ className: cn("dg-body", alternatingRows && "dg-alternating", classNames.body),
1535
+ children: [
1536
+ isLoading && /* @__PURE__ */ jsx(
1537
+ DataGridSkeleton,
1538
+ {
1539
+ columns,
1540
+ rowCount: skeletonRowCount,
1541
+ showCheckbox: showBulkActions,
1542
+ showActions: showActionColumn,
1543
+ showExpander: showExpanderColumn
1544
+ }
1545
+ ),
1546
+ !isLoading && data.length === 0 && /* @__PURE__ */ jsx(TableRow, { className: "dg-row dg-row--empty", children: /* @__PURE__ */ jsx(
1547
+ TableCell,
1548
+ {
1549
+ colSpan: totalColSpan,
1550
+ className: cn("dg-cell dg-cell--empty h-24 text-center", classNames.empty),
1551
+ children: emptyComponent || /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: emptyMessage })
1552
+ }
1553
+ ) }),
1554
+ !isLoading && sortedData.map((row, rowIndex) => renderRow(row, rowIndex))
1555
+ ]
1556
+ }
1557
+ )
1558
+ ] })
1559
+ }
1560
+ ),
1561
+ pagination && /* @__PURE__ */ jsx(DataGridPagination, { config: pagination, className: classNames.pagination })
1562
+ ]
1563
+ }
1564
+ );
1565
+ }
1566
+
1567
+ export { DataGrid, exportToCsv, exportToPrint, formatCurrency, formatDateValue, formatNumber, formatValue, getCellExportValue };
1568
+ //# sourceMappingURL=index.js.map
1569
+ //# sourceMappingURL=index.js.map