@acsrocha/ui 1.0.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,1576 @@
1
+ import * as React3 from 'react';
2
+ import React3__default, { forwardRef, useState, useEffect, useRef, useMemo, useCallback, useLayoutEffect } from 'react';
3
+ import { Check, Grid3x3, List, Table, LayoutGrid, RefreshCw, Loader2, Filter, Bookmark, History, Download, Upload, Save, XCircle, ChevronDown, ChevronRight, Activity, Trash2, X, AlertTriangle, CheckCircle, Database, Plus, Edit, Shield } from 'lucide-react';
4
+ import { cva } from 'class-variance-authority';
5
+ import { clsx } from 'clsx';
6
+ import { twMerge } from 'tailwind-merge';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+ import { AnimatePresence, motion } from 'framer-motion';
9
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
10
+ import { useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
11
+ import { createPortal } from 'react-dom';
12
+
13
+ function cn(...inputs) {
14
+ return twMerge(clsx(inputs));
15
+ }
16
+ var buttonVariants = cva(
17
+ "relative inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-semibold ring-offset-background transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:scale-[1.03] active:scale-[0.98] overflow-hidden group",
18
+ {
19
+ variants: {
20
+ variant: {
21
+ default: "bg-gradient-to-br from-blue-500 via-blue-600 to-blue-700 text-white shadow-lg shadow-blue-500/25 hover:shadow-xl hover:shadow-blue-500/40 border border-blue-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
22
+ destructive: "bg-gradient-to-br from-red-500 via-red-600 to-red-700 text-white shadow-lg shadow-red-500/25 hover:shadow-xl hover:shadow-red-500/40 border border-red-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
23
+ outline: "border-2 border-slate-300 bg-white/80 backdrop-blur-sm hover:bg-white hover:border-blue-400 hover:text-blue-700 text-slate-700 shadow-sm hover:shadow-lg hover:shadow-blue-500/10 before:absolute before:inset-0 before:bg-gradient-to-br before:from-blue-50/50 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
24
+ secondary: "bg-gradient-to-br from-slate-500 via-slate-600 to-slate-700 text-white shadow-lg shadow-slate-500/25 hover:shadow-xl hover:shadow-slate-500/40 border border-slate-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
25
+ ghost: "hover:bg-slate-100/80 hover:text-slate-900 shadow-none hover:shadow-md text-slate-600 backdrop-blur-sm before:absolute before:inset-0 before:bg-gradient-to-br before:from-slate-100/50 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
26
+ link: "text-blue-600 underline-offset-4 hover:underline shadow-none hover:shadow-none hover:scale-100 hover:text-blue-700 relative z-10",
27
+ success: "bg-gradient-to-br from-emerald-500 via-emerald-600 to-emerald-700 text-white shadow-lg shadow-emerald-500/25 hover:shadow-xl hover:shadow-emerald-500/40 border border-emerald-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
28
+ warning: "bg-gradient-to-br from-amber-500 via-amber-600 to-amber-700 text-white shadow-lg shadow-amber-500/25 hover:shadow-xl hover:shadow-amber-500/40 border border-amber-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity"
29
+ },
30
+ size: {
31
+ default: "h-11 px-6 py-2.5 text-sm",
32
+ sm: "h-9 px-4 text-xs",
33
+ lg: "h-13 px-8 text-base",
34
+ icon: "h-11 w-11"
35
+ }
36
+ },
37
+ defaultVariants: {
38
+ variant: "default",
39
+ size: "default"
40
+ }
41
+ }
42
+ );
43
+ var Button = React3.forwardRef(
44
+ ({ className, variant, size, ...props }, ref) => {
45
+ return /* @__PURE__ */ jsx(
46
+ "button",
47
+ {
48
+ className: cn(buttonVariants({ variant, size, className })),
49
+ ref,
50
+ ...props,
51
+ children: /* @__PURE__ */ jsx("span", { className: "relative z-10 flex items-center justify-center gap-2", children: props.children })
52
+ }
53
+ );
54
+ }
55
+ );
56
+ Button.displayName = "Button";
57
+ var badgeVariants = cva(
58
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none",
59
+ {
60
+ variants: {
61
+ variant: {
62
+ default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
63
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
64
+ destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
65
+ outline: "text-foreground",
66
+ success: "border-transparent bg-emerald-500 text-white hover:bg-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400",
67
+ warning: "border-transparent bg-amber-500 text-white hover:bg-amber-600 dark:bg-amber-900/30 dark:text-amber-400"
68
+ }
69
+ },
70
+ defaultVariants: {
71
+ variant: "default"
72
+ }
73
+ }
74
+ );
75
+ function Badge({ className, variant, ...props }) {
76
+ return /* @__PURE__ */ jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
77
+ }
78
+ var VIEW_MODE_CONFIG = {
79
+ cards: { value: "cards", icon: LayoutGrid, label: "Cards" },
80
+ table: { value: "table", icon: Table, label: "Tabela" },
81
+ list: { value: "list", icon: List, label: "Lista" },
82
+ grid: { value: "grid", icon: Grid3x3, label: "Grade" }
83
+ };
84
+ var BTN_H = "h-9";
85
+ var CTRL_BTN = `relative z-10 inline-flex items-center justify-center gap-1.5 px-3 text-xs font-semibold whitespace-nowrap transition-colors duration-150`;
86
+ function SelectorBar({ children, activeIndex }) {
87
+ const containerRef = useRef(null);
88
+ const [highlight, setHighlight] = useState({ left: 0, width: 0 });
89
+ const measure = () => {
90
+ const container = containerRef.current;
91
+ if (!container) return;
92
+ const buttons = container.querySelectorAll("button");
93
+ const active = buttons[activeIndex];
94
+ if (!active) return;
95
+ setHighlight({ left: active.offsetLeft, width: active.offsetWidth });
96
+ };
97
+ useLayoutEffect(() => {
98
+ measure();
99
+ }, [activeIndex, children]);
100
+ useLayoutEffect(() => {
101
+ const container = containerRef.current;
102
+ if (!container) return;
103
+ const observer = new ResizeObserver(measure);
104
+ observer.observe(container);
105
+ return () => observer.disconnect();
106
+ }, []);
107
+ return /* @__PURE__ */ jsxs(
108
+ "div",
109
+ {
110
+ ref: containerRef,
111
+ className: `relative inline-flex items-stretch border border-input bg-background rounded-md ${BTN_H} p-0.5 gap-0.5`,
112
+ children: [
113
+ /* @__PURE__ */ jsx(
114
+ "div",
115
+ {
116
+ className: "absolute top-0.5 bottom-0.5 bg-blue-600 rounded transition-all duration-200 ease-out pointer-events-none",
117
+ style: { left: highlight.left, width: highlight.width }
118
+ }
119
+ ),
120
+ children
121
+ ]
122
+ }
123
+ );
124
+ }
125
+ function PageHeader({
126
+ title,
127
+ subtitle,
128
+ icon: Icon,
129
+ actions,
130
+ badge,
131
+ viewMode,
132
+ onViewModeChange,
133
+ viewModeOptions = ["table", "cards"],
134
+ loading = false,
135
+ tabs,
136
+ activeTab,
137
+ onTabChange,
138
+ onRefresh
139
+ }) {
140
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between", children: [
141
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
142
+ Icon && /* @__PURE__ */ jsx("div", { className: "bg-primary/10 rounded-lg flex-shrink-0 p-2", children: /* @__PURE__ */ jsx(Icon, { className: `w-6 h-6 text-primary ${loading ? "animate-pulse" : ""}` }) }),
143
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
144
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
145
+ /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold whitespace-nowrap", children: title }),
146
+ badge && /* @__PURE__ */ jsx(Badge, { variant: badge.variant || "secondary", className: "whitespace-nowrap", children: badge.label })
147
+ ] }),
148
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs mt-0.5", children: subtitle })
149
+ ] })
150
+ ] }),
151
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
152
+ actions,
153
+ tabs && onTabChange && /* @__PURE__ */ jsx(SelectorBar, { activeIndex: tabs.findIndex((t) => t.value === activeTab), children: tabs.map((t) => /* @__PURE__ */ jsxs(
154
+ "button",
155
+ {
156
+ onClick: () => onTabChange(t.value),
157
+ className: `${CTRL_BTN} ${activeTab === t.value ? "text-white" : "text-muted-foreground hover:text-foreground"}`,
158
+ children: [
159
+ /* @__PURE__ */ jsx(t.icon, { className: "w-3.5 h-3.5 shrink-0" }),
160
+ t.label,
161
+ (t.badge ?? 0) > 0 && /* @__PURE__ */ jsx("span", { className: "ml-1 bg-red-500 text-white text-[10px] font-bold rounded-full min-w-[18px] h-[18px] flex items-center justify-center px-1", children: t.badge })
162
+ ]
163
+ },
164
+ t.value
165
+ )) }),
166
+ viewMode && onViewModeChange && viewModeOptions.length > 1 && /* @__PURE__ */ jsx(SelectorBar, { activeIndex: viewModeOptions.indexOf(viewMode), children: viewModeOptions.map((mode) => {
167
+ const config = VIEW_MODE_CONFIG[mode];
168
+ return /* @__PURE__ */ jsxs(
169
+ "button",
170
+ {
171
+ onClick: () => onViewModeChange(mode),
172
+ className: `${CTRL_BTN} ${viewMode === mode ? "text-white" : "text-muted-foreground hover:text-foreground"}`,
173
+ children: [
174
+ /* @__PURE__ */ jsx(config.icon, { className: "w-3.5 h-3.5" }),
175
+ config.label
176
+ ]
177
+ },
178
+ mode
179
+ );
180
+ }) }),
181
+ onRefresh && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: onRefresh, disabled: loading, className: "gap-1.5 text-xs font-semibold", children: [
182
+ /* @__PURE__ */ jsx(RefreshCw, { className: `w-3.5 h-3.5 ${loading ? "animate-spin" : ""}` }),
183
+ " Atualizar"
184
+ ] })
185
+ ] })
186
+ ] });
187
+ }
188
+ var Card = React3.forwardRef(
189
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
190
+ "div",
191
+ {
192
+ ref,
193
+ className: cn("rounded-lg border bg-card text-card-foreground shadow-sm", className),
194
+ ...props
195
+ }
196
+ )
197
+ );
198
+ Card.displayName = "Card";
199
+ var CardHeader = React3.forwardRef(
200
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
201
+ );
202
+ CardHeader.displayName = "CardHeader";
203
+ var CardTitle = React3.forwardRef(
204
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
205
+ "h3",
206
+ {
207
+ ref,
208
+ className: cn("text-2xl font-semibold leading-none tracking-tight", className),
209
+ ...props
210
+ }
211
+ )
212
+ );
213
+ CardTitle.displayName = "CardTitle";
214
+ var CardDescription = React3.forwardRef(
215
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props })
216
+ );
217
+ CardDescription.displayName = "CardDescription";
218
+ var CardContent = React3.forwardRef(
219
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props })
220
+ );
221
+ CardContent.displayName = "CardContent";
222
+ var CardFooter = React3.forwardRef(
223
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center p-6 pt-0", className), ...props })
224
+ );
225
+ CardFooter.displayName = "CardFooter";
226
+ var STAT_ACCENT_SEQUENCE = ["blue", "green", "amber", "purple", "teal", "rose"];
227
+ var accentLight = {
228
+ blue: { border: "border-l-blue-400", icon: "bg-blue-100 text-blue-600", text: "text-blue-600" },
229
+ purple: { border: "border-l-purple-400", icon: "bg-purple-100 text-purple-600", text: "text-purple-600" },
230
+ green: { border: "border-l-emerald-400", icon: "bg-emerald-100 text-emerald-600", text: "text-emerald-600" },
231
+ amber: { border: "border-l-amber-400", icon: "bg-amber-100 text-amber-600", text: "text-amber-600" },
232
+ teal: { border: "border-l-teal-400", icon: "bg-teal-100 text-teal-600", text: "text-teal-600" },
233
+ rose: { border: "border-l-rose-400", icon: "bg-rose-100 text-rose-600", text: "text-rose-600" }
234
+ };
235
+ var accentDark = {
236
+ blue: { gradient: "bg-gradient-to-br from-blue-950 to-blue-900", icon: "bg-black/20 text-white/70" },
237
+ purple: { gradient: "bg-gradient-to-br from-purple-950 to-purple-900", icon: "bg-black/20 text-white/70" },
238
+ green: { gradient: "bg-gradient-to-br from-green-950 to-green-900", icon: "bg-black/20 text-white/70" },
239
+ amber: { gradient: "bg-gradient-to-br from-orange-950 to-orange-900", icon: "bg-black/20 text-white/70" },
240
+ teal: { gradient: "bg-gradient-to-br from-emerald-950 to-emerald-900", icon: "bg-black/20 text-white/70" },
241
+ rose: { gradient: "bg-gradient-to-br from-red-950 to-red-900", icon: "bg-black/20 text-white/70" }
242
+ };
243
+ function StatCard({
244
+ icon: Icon,
245
+ title,
246
+ label,
247
+ value,
248
+ subtitle,
249
+ sublabel,
250
+ gradient,
251
+ accentColor,
252
+ color,
253
+ onClick,
254
+ variant = "default",
255
+ loading = false,
256
+ active = false
257
+ }) {
258
+ const displayLabel = title || label;
259
+ const displaySublabel = subtitle || sublabel;
260
+ const isClickable = !!onClick;
261
+ const [isDark, setIsDark] = useState(
262
+ () => document.documentElement.classList.contains("dark")
263
+ );
264
+ useEffect(() => {
265
+ const observer = new MutationObserver(() => {
266
+ setIsDark(document.documentElement.classList.contains("dark"));
267
+ });
268
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
269
+ return () => observer.disconnect();
270
+ }, []);
271
+ if (variant === "slim") {
272
+ return /* @__PURE__ */ jsx(
273
+ Card,
274
+ {
275
+ className: `border-0 shadow-md transition-all ${isClickable ? "cursor-pointer hover:shadow-lg" : ""} ${active ? "ring-2 ring-primary" : ""}`,
276
+ onClick,
277
+ children: /* @__PURE__ */ jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
278
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] uppercase tracking-wide text-muted-foreground mb-1", children: displayLabel }),
279
+ /* @__PURE__ */ jsx("p", { className: "text-base font-bold", children: loading ? /* @__PURE__ */ jsx(Loader2, { className: "w-4 h-4 animate-spin mx-auto" }) : value })
280
+ ] }) })
281
+ }
282
+ );
283
+ }
284
+ let cardClass = "";
285
+ let iconClass = "";
286
+ let valueClass = "";
287
+ if (accentColor) {
288
+ if (isDark) {
289
+ cardClass = `border-0 ${accentDark[accentColor].gradient}`;
290
+ iconClass = accentDark[accentColor].icon;
291
+ valueClass = "text-foreground";
292
+ } else {
293
+ cardClass = `border border-border border-l-4 ${accentLight[accentColor].border} bg-card shadow-sm`;
294
+ iconClass = accentLight[accentColor].icon;
295
+ valueClass = accentLight[accentColor].text;
296
+ }
297
+ } else {
298
+ cardClass = `border-0 ${gradient ? `bg-gradient-to-br ${gradient}` : "shadow-md"}`;
299
+ iconClass = color || (gradient ? "bg-black/10 dark:bg-white/10" : "bg-primary/10");
300
+ valueClass = "";
301
+ }
302
+ return /* @__PURE__ */ jsx(
303
+ Card,
304
+ {
305
+ className: `transition-all overflow-hidden ${cardClass} ${isClickable ? "cursor-pointer hover:shadow-md hover:scale-[1.02]" : ""} ${active ? "ring-2 ring-primary shadow-md scale-[1.02]" : ""}`,
306
+ onClick,
307
+ children: /* @__PURE__ */ jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
308
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
309
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] uppercase tracking-wide font-medium text-muted-foreground mb-1", children: displayLabel }),
310
+ /* @__PURE__ */ jsx("div", { className: "flex items-baseline gap-2", children: /* @__PURE__ */ jsx("h3", { className: `text-2xl font-bold leading-none ${valueClass}`, children: loading ? /* @__PURE__ */ jsx(Loader2, { className: "w-5 h-5 animate-spin" }) : value }) }),
311
+ displaySublabel && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground mt-1", children: displaySublabel })
312
+ ] }),
313
+ Icon && /* @__PURE__ */ jsx("div", { className: `p-1.5 rounded-lg ${iconClass}`, children: /* @__PURE__ */ jsx(Icon, { className: "w-4 h-4" }) })
314
+ ] }) })
315
+ }
316
+ );
317
+ }
318
+ var COLS_CLASS = {
319
+ 2: "grid-cols-1 md:grid-cols-2",
320
+ 3: "grid-cols-1 md:grid-cols-3",
321
+ 4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
322
+ 5: "grid-cols-1 md:grid-cols-3 lg:grid-cols-5",
323
+ 6: "grid-cols-1 md:grid-cols-3 lg:grid-cols-6"
324
+ };
325
+ function resolveStatsCols(count, override) {
326
+ const cols = override ?? Math.min(count, 6);
327
+ return COLS_CLASS[cols] ?? COLS_CLASS[6];
328
+ }
329
+ function PageLayout({
330
+ header,
331
+ stats,
332
+ statsCols,
333
+ content,
334
+ viewMode,
335
+ tableContent,
336
+ cardContent,
337
+ paddingX = "px-3",
338
+ paddingTop = "pt-3",
339
+ paddingBottom = "pb-[2px]",
340
+ gapHeaderStats = "mt-4",
341
+ gapStatsContent = "mt-4",
342
+ maxWidth = "max-w-[1600px]",
343
+ extras,
344
+ fillHeight = true
345
+ }) {
346
+ const mainContent = viewMode !== void 0 ? viewMode === "table" ? tableContent : cardContent : content;
347
+ return /* @__PURE__ */ jsxs("main", { className: `gradient-bg ${fillHeight ? "h-full flex flex-col" : ""} ${paddingX} ${paddingTop} ${paddingBottom}`, children: [
348
+ /* @__PURE__ */ jsxs("div", { className: `${maxWidth} mx-auto w-full ${fillHeight ? "flex flex-col flex-1 min-h-0" : ""}`, children: [
349
+ header,
350
+ stats && stats.length > 0 && /* @__PURE__ */ jsx("div", { className: `grid ${resolveStatsCols(stats.length, statsCols)} gap-3 ${gapHeaderStats}`, children: stats.map((stat, i) => {
351
+ const needsDefault = !stat.accentColor && !stat.gradient;
352
+ return /* @__PURE__ */ jsx(
353
+ StatCard,
354
+ {
355
+ ...stat,
356
+ accentColor: needsDefault ? STAT_ACCENT_SEQUENCE[i % STAT_ACCENT_SEQUENCE.length] : stat.accentColor
357
+ },
358
+ stat.title ?? stat.label ?? i
359
+ );
360
+ }) }),
361
+ /* @__PURE__ */ jsx("div", { className: `${gapStatsContent} ${fillHeight ? "flex flex-col flex-1 min-h-0" : ""}`, children: mainContent })
362
+ ] }),
363
+ extras
364
+ ] });
365
+ }
366
+ var Table2 = React3.forwardRef(
367
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full", children: /* @__PURE__ */ jsx(
368
+ "table",
369
+ {
370
+ ref,
371
+ className: cn("w-full caption-bottom text-sm bg-transparent", className),
372
+ ...props
373
+ }
374
+ ) })
375
+ );
376
+ Table2.displayName = "Table";
377
+ var TableHeader = React3.forwardRef(
378
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
379
+ "thead",
380
+ {
381
+ ref,
382
+ className: cn(
383
+ "[&_tr]:border-b [&_tr]:border-border [&_tr]:bg-muted/60 dark:[&_tr]:bg-gradient-to-b dark:[&_tr]:from-slate-700 dark:[&_tr]:to-slate-800 dark:[&_tr]:border-cyan-400/60 dark:[&_tr]:border-b-2",
384
+ className
385
+ ),
386
+ ...props
387
+ }
388
+ )
389
+ );
390
+ TableHeader.displayName = "TableHeader";
391
+ var TableBody = React3.forwardRef(
392
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("tbody", { ref, className: cn("[&_tr:last-child]:border-0 bg-transparent", className), ...props })
393
+ );
394
+ TableBody.displayName = "TableBody";
395
+ var TableFooter = React3.forwardRef(
396
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
397
+ "tfoot",
398
+ {
399
+ ref,
400
+ className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className),
401
+ ...props
402
+ }
403
+ )
404
+ );
405
+ TableFooter.displayName = "TableFooter";
406
+ var TableRow = React3.forwardRef(
407
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
408
+ "tr",
409
+ {
410
+ ref,
411
+ className: cn(
412
+ "border-b border-border/60 transition-colors hover:bg-muted/40 data-[state=selected]:bg-muted/30 text-foreground even:bg-muted/20",
413
+ className
414
+ ),
415
+ ...props
416
+ }
417
+ )
418
+ );
419
+ TableRow.displayName = "TableRow";
420
+ var TableHead = React3.forwardRef(
421
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
422
+ "th",
423
+ {
424
+ ref,
425
+ className: cn(
426
+ "h-9 px-4 text-left align-middle font-medium text-muted-foreground dark:text-slate-300 uppercase text-[10px] tracking-wide border-r border-border/50 dark:border-slate-600/70 last:border-r-0 [&:has([role=checkbox])]:pr-0",
427
+ className
428
+ ),
429
+ ...props
430
+ }
431
+ )
432
+ );
433
+ TableHead.displayName = "TableHead";
434
+ var TableCell = React3.forwardRef(
435
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
436
+ "td",
437
+ {
438
+ ref,
439
+ className: cn("px-4 py-1.5 align-middle [&:has([role=checkbox])]:pr-0 text-foreground/90 text-xs", className),
440
+ ...props
441
+ }
442
+ )
443
+ );
444
+ TableCell.displayName = "TableCell";
445
+ var TableCaption = React3.forwardRef(
446
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })
447
+ );
448
+ TableCaption.displayName = "TableCaption";
449
+ var Checkbox = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
450
+ CheckboxPrimitive.Root,
451
+ {
452
+ ref,
453
+ className: cn(
454
+ "peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
455
+ className
456
+ ),
457
+ ...props,
458
+ children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: cn("flex items-center justify-center text-current"), children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) })
459
+ }
460
+ ));
461
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
462
+ var SmartFilterPanel = ({
463
+ filterGroups,
464
+ searchValue = "",
465
+ onSearchChange,
466
+ searchPlaceholder = "Buscar...",
467
+ resultsCount,
468
+ onClearAll,
469
+ defaultExpanded = false,
470
+ persistKey,
471
+ enablePresets = false,
472
+ enableUrlSync = false,
473
+ enableHistory = false,
474
+ maxHistoryItems = 10,
475
+ onFiltersChange
476
+ }) => {
477
+ const [showFilters, setShowFilters] = useState(() => {
478
+ if (!persistKey) return defaultExpanded;
479
+ const saved = localStorage.getItem(`showFilters_${persistKey}`);
480
+ return saved !== null ? saved === "true" : defaultExpanded;
481
+ });
482
+ const [presets, setPresets] = useState([]);
483
+ const [showPresets, setShowPresets] = useState(false);
484
+ const [history, setHistory] = useState([]);
485
+ const [showHistory, setShowHistory] = useState(false);
486
+ const [showSavePresetModal, setShowSavePresetModal] = useState(false);
487
+ const [presetName, setPresetName] = useState("");
488
+ const [localSearch, setLocalSearch] = useState(searchValue);
489
+ const debounceRef = useRef(null);
490
+ useEffect(() => {
491
+ if (searchValue === "") setLocalSearch("");
492
+ }, [searchValue]);
493
+ const activeFiltersCount = useMemo(
494
+ () => filterGroups.filter((g) => g.selectedValues.length > 0).length + (searchValue ? 1 : 0),
495
+ [filterGroups, searchValue]
496
+ );
497
+ const hasActiveFilters = activeFiltersCount > 0;
498
+ const currentFiltersState = useMemo(
499
+ () => filterGroups.reduce((acc, group) => {
500
+ acc[group.key] = group.selectedValues;
501
+ return acc;
502
+ }, {}),
503
+ [filterGroups]
504
+ );
505
+ useEffect(() => {
506
+ if (!persistKey) return;
507
+ const saved = localStorage.getItem(`filters_${persistKey}`);
508
+ if (saved) {
509
+ try {
510
+ const parsed = JSON.parse(saved);
511
+ Object.entries(parsed).forEach(([key, values]) => {
512
+ const group = filterGroups.find((g) => g.key === key);
513
+ if (group) group.onChange(values);
514
+ });
515
+ } catch (e) {
516
+ console.error("Erro ao carregar filtros:", e);
517
+ }
518
+ }
519
+ if (enablePresets) {
520
+ const savedPresets = localStorage.getItem(`presets_${persistKey}`);
521
+ if (savedPresets) {
522
+ try {
523
+ setPresets(JSON.parse(savedPresets));
524
+ } catch (e) {
525
+ console.error(e);
526
+ }
527
+ }
528
+ }
529
+ if (enableHistory) {
530
+ const savedHistory = localStorage.getItem(`history_${persistKey}`);
531
+ if (savedHistory) {
532
+ try {
533
+ setHistory(JSON.parse(savedHistory));
534
+ } catch (e) {
535
+ console.error(e);
536
+ }
537
+ }
538
+ }
539
+ }, [persistKey]);
540
+ useEffect(() => {
541
+ if (!persistKey) return;
542
+ localStorage.setItem(`filters_${persistKey}`, JSON.stringify(currentFiltersState));
543
+ onFiltersChange?.(currentFiltersState);
544
+ }, [currentFiltersState, persistKey, onFiltersChange]);
545
+ useEffect(() => {
546
+ if (!enableUrlSync) return;
547
+ const params = new URLSearchParams(window.location.search);
548
+ Object.entries(currentFiltersState).forEach(([key, values]) => {
549
+ if (values.length > 0) params.set(key, values.join(","));
550
+ else params.delete(key);
551
+ });
552
+ if (searchValue) params.set("search", searchValue);
553
+ else params.delete("search");
554
+ window.history.replaceState({}, "", `${window.location.pathname}?${params.toString()}`);
555
+ }, [currentFiltersState, searchValue, enableUrlSync]);
556
+ const handleClearAll = useCallback(() => {
557
+ filterGroups.forEach((group) => group.onChange([]));
558
+ onSearchChange?.("");
559
+ onClearAll?.();
560
+ }, [filterGroups, onSearchChange, onClearAll]);
561
+ const toggleOption = useCallback((group, value) => {
562
+ if (group.selectedValues.includes(value)) group.onChange(group.selectedValues.filter((v) => v !== value));
563
+ else group.onChange([...group.selectedValues, value]);
564
+ }, []);
565
+ const toggleAll = useCallback((group) => {
566
+ const allValues = group.options.map((o) => o.value);
567
+ if (group.selectedValues.length === allValues.length) group.onChange([]);
568
+ else group.onChange(allValues);
569
+ }, []);
570
+ const confirmSavePreset = useCallback(() => {
571
+ if (!presetName.trim()) return;
572
+ const newPreset = { id: Date.now().toString(), name: presetName.trim(), filters: currentFiltersState, searchValue, createdAt: /* @__PURE__ */ new Date() };
573
+ const updated = [...presets, newPreset];
574
+ setPresets(updated);
575
+ if (persistKey) localStorage.setItem(`presets_${persistKey}`, JSON.stringify(updated));
576
+ setPresetName("");
577
+ setShowSavePresetModal(false);
578
+ }, [presets, currentFiltersState, searchValue, persistKey, presetName]);
579
+ const loadPreset = useCallback((preset) => {
580
+ Object.entries(preset.filters).forEach(([key, values]) => {
581
+ const group = filterGroups.find((g) => g.key === key);
582
+ if (group) group.onChange(values);
583
+ });
584
+ if (preset.searchValue) onSearchChange?.(preset.searchValue);
585
+ setShowPresets(false);
586
+ setShowHistory(false);
587
+ }, [filterGroups, onSearchChange]);
588
+ const deletePreset = useCallback((id) => {
589
+ const updated = presets.filter((p) => p.id !== id);
590
+ setPresets(updated);
591
+ if (persistKey) localStorage.setItem(`presets_${persistKey}`, JSON.stringify(updated));
592
+ }, [presets, persistKey]);
593
+ const addToHistory = useCallback(() => {
594
+ if (!enableHistory || !hasActiveFilters) return;
595
+ const newEntry = { id: Date.now().toString(), name: `Filtro ${(/* @__PURE__ */ new Date()).toLocaleString()}`, filters: currentFiltersState, searchValue, createdAt: /* @__PURE__ */ new Date() };
596
+ const updated = [newEntry, ...history].slice(0, maxHistoryItems);
597
+ setHistory(updated);
598
+ if (persistKey) localStorage.setItem(`history_${persistKey}`, JSON.stringify(updated));
599
+ }, [enableHistory, hasActiveFilters, currentFiltersState, searchValue, history, maxHistoryItems, persistKey]);
600
+ useEffect(() => {
601
+ if (hasActiveFilters) {
602
+ const timer = setTimeout(addToHistory, 2e3);
603
+ return () => clearTimeout(timer);
604
+ }
605
+ }, [hasActiveFilters, addToHistory]);
606
+ const exportFilters = useCallback(() => {
607
+ const data = { filters: currentFiltersState, searchValue, exportedAt: (/* @__PURE__ */ new Date()).toISOString() };
608
+ const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
609
+ const url = URL.createObjectURL(blob);
610
+ const a = document.createElement("a");
611
+ a.href = url;
612
+ a.download = `filters_${persistKey || "export"}_${Date.now()}.json`;
613
+ a.click();
614
+ URL.revokeObjectURL(url);
615
+ }, [currentFiltersState, searchValue, persistKey]);
616
+ const importFilters = useCallback(() => {
617
+ const input = document.createElement("input");
618
+ input.type = "file";
619
+ input.accept = "application/json";
620
+ input.onchange = (e) => {
621
+ const file = e.target.files?.[0];
622
+ if (!file) return;
623
+ const reader = new FileReader();
624
+ reader.onload = (e2) => {
625
+ try {
626
+ const data = JSON.parse(e2.target?.result);
627
+ Object.entries(data.filters).forEach(([key, values]) => {
628
+ const group = filterGroups.find((g) => g.key === key);
629
+ if (group) group.onChange(values);
630
+ });
631
+ if (data.searchValue) onSearchChange?.(data.searchValue);
632
+ } catch {
633
+ alert("Erro ao importar filtros");
634
+ }
635
+ };
636
+ reader.readAsText(file);
637
+ };
638
+ input.click();
639
+ }, [filterGroups, onSearchChange]);
640
+ const defaultAllColor = { bg: "bg-slate-100", text: "text-slate-800", border: "border-slate-300", darkBg: "dark:bg-slate-900/30", darkText: "dark:text-slate-300", darkBorder: "dark:border-slate-800" };
641
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
642
+ /* @__PURE__ */ jsx(Card, { className: "border-border/30 shadow-xl", children: /* @__PURE__ */ jsxs(CardContent, { className: `transition-all ${showFilters ? "p-3" : "p-2.5"}`, children: [
643
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
644
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
645
+ /* @__PURE__ */ jsx("div", { className: "p-1 bg-primary/10 rounded", children: /* @__PURE__ */ jsx(Filter, { className: "w-3 h-3 text-primary" }) }),
646
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Filtros" }),
647
+ hasActiveFilters && /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "bg-primary/10 text-primary border-primary/20", children: [
648
+ activeFiltersCount,
649
+ " ativo",
650
+ activeFiltersCount > 1 ? "s" : ""
651
+ ] })
652
+ ] }),
653
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
654
+ enablePresets && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setShowPresets(!showPresets), title: "Presets", disabled: !showFilters, children: /* @__PURE__ */ jsx(Bookmark, { className: "w-4 h-4" }) }),
655
+ enableHistory && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setShowHistory(!showHistory), title: "Hist\xF3rico", disabled: !showFilters, children: /* @__PURE__ */ jsx(History, { className: "w-4 h-4" }) }),
656
+ persistKey && /* @__PURE__ */ jsxs(Fragment, { children: [
657
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: exportFilters, title: "Exportar", disabled: !showFilters, children: /* @__PURE__ */ jsx(Download, { className: "w-4 h-4" }) }),
658
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: importFilters, title: "Importar", disabled: !showFilters, children: /* @__PURE__ */ jsx(Upload, { className: "w-4 h-4" }) })
659
+ ] }),
660
+ enablePresets && hasActiveFilters && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setShowSavePresetModal(true), title: "Salvar Preset", disabled: !showFilters, children: /* @__PURE__ */ jsx(Save, { className: "w-4 h-4" }) }),
661
+ hasActiveFilters && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: handleClearAll, children: [
662
+ /* @__PURE__ */ jsx(XCircle, { className: "w-4 h-4 mr-2" }),
663
+ "Limpar"
664
+ ] }),
665
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => {
666
+ const next = !showFilters;
667
+ setShowFilters(next);
668
+ if (persistKey) localStorage.setItem(`showFilters_${persistKey}`, String(next));
669
+ }, children: showFilters ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" }) })
670
+ ] })
671
+ ] }),
672
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showPresets && presets.length > 0 && /* @__PURE__ */ jsxs(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, className: "mt-3 p-3 bg-muted/30 rounded-lg border", children: [
673
+ /* @__PURE__ */ jsx("div", { className: "text-xs font-semibold mb-2", children: "Presets Salvos" }),
674
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: presets.map((preset) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-2 py-1 bg-background rounded border", children: [
675
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => loadPreset(preset), className: "h-6 px-2", children: preset.name }),
676
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => deletePreset(preset.id), className: "h-6 w-6 p-0", children: /* @__PURE__ */ jsx(XCircle, { className: "w-3 h-3" }) })
677
+ ] }, preset.id)) })
678
+ ] }) }),
679
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showHistory && history.length > 0 && /* @__PURE__ */ jsxs(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, className: "mt-3 p-3 bg-muted/30 rounded-lg border", children: [
680
+ /* @__PURE__ */ jsx("div", { className: "text-xs font-semibold mb-2", children: "Hist\xF3rico Recente" }),
681
+ /* @__PURE__ */ jsx("div", { className: "space-y-1", children: history.map((entry) => /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => loadPreset(entry), className: "w-full justify-start h-8 text-xs", children: [
682
+ /* @__PURE__ */ jsx(History, { className: "w-3 h-3 mr-2" }),
683
+ entry.name
684
+ ] }, entry.id)) })
685
+ ] }) }),
686
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showFilters && /* @__PURE__ */ jsx(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, transition: { duration: 0.3 }, style: { overflow: "visible" }, children: /* @__PURE__ */ jsxs("div", { className: "space-y-3 mt-3", children: [
687
+ onSearchChange && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
688
+ /* @__PURE__ */ jsx("span", { className: "absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground text-xs pointer-events-none", children: "\u{1F50D}" }),
689
+ /* @__PURE__ */ jsx(
690
+ "input",
691
+ {
692
+ type: "text",
693
+ placeholder: searchPlaceholder,
694
+ value: localSearch,
695
+ onChange: (e) => {
696
+ const val = e.target.value;
697
+ setLocalSearch(val);
698
+ if (debounceRef.current) clearTimeout(debounceRef.current);
699
+ debounceRef.current = setTimeout(() => onSearchChange(val), 900);
700
+ },
701
+ className: "w-full pl-8 pr-3 h-8 text-xs py-1.5 border border-input rounded-md bg-slate-900/50 dark:bg-slate-950/50 text-foreground focus:outline-none focus:border-primary/50"
702
+ }
703
+ )
704
+ ] }),
705
+ filterGroups.map((group) => {
706
+ const allValues = group.options.map((o) => o.value);
707
+ const allSelected = group.selectedValues.length === allValues.length;
708
+ const allColor = group.allColor || defaultAllColor;
709
+ if (group.renderType === "select") {
710
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
711
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium", children: group.label }),
712
+ /* @__PURE__ */ jsx(
713
+ "select",
714
+ {
715
+ value: group.selectedValues[0] || "",
716
+ onChange: (e) => group.onChange(e.target.value ? [e.target.value] : []),
717
+ className: "w-full px-3 py-2 text-sm border border-input rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring",
718
+ children: group.options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
719
+ }
720
+ )
721
+ ] }, group.key);
722
+ }
723
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
724
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium", children: group.label }),
725
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
726
+ group.allLabel && /* @__PURE__ */ jsxs(
727
+ Button,
728
+ {
729
+ variant: "outline",
730
+ size: "sm",
731
+ onClick: () => toggleAll(group),
732
+ className: `rounded-full ${allColor.bg} ${allColor.text} ${allColor.darkBg} ${allColor.darkText} ${allSelected ? `${allColor.border} ${allColor.darkBorder}` : "border-transparent"}`,
733
+ children: [
734
+ group.allLabel,
735
+ " ",
736
+ allSelected && "\u2713"
737
+ ]
738
+ }
739
+ ),
740
+ group.options.map((option) => {
741
+ const isSelected = group.selectedValues.includes(option.value);
742
+ return /* @__PURE__ */ jsxs(
743
+ Button,
744
+ {
745
+ variant: "outline",
746
+ size: "sm",
747
+ onClick: () => toggleOption(group, option.value),
748
+ className: `rounded-full ${option.color.bg} ${option.color.text} ${option.color.darkBg} ${option.color.darkText} ${isSelected ? `${option.color.border} ${option.color.darkBorder}` : "border-transparent"}`,
749
+ children: [
750
+ option.emoji && `${option.emoji} `,
751
+ option.label
752
+ ]
753
+ },
754
+ option.value
755
+ );
756
+ })
757
+ ] })
758
+ ] }, group.key);
759
+ }),
760
+ resultsCount !== void 0 && /* @__PURE__ */ jsx("div", { className: "pt-2 border-t", children: /* @__PURE__ */ jsxs(Badge, { className: "px-3 py-1.5 bg-primary/10 text-primary border-primary/20", children: [
761
+ /* @__PURE__ */ jsx(Activity, { className: "w-3.5 h-3.5 mr-1.5" }),
762
+ resultsCount,
763
+ " resultado",
764
+ resultsCount !== 1 ? "s" : ""
765
+ ] }) })
766
+ ] }) }) })
767
+ ] }) }),
768
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showSavePresetModal && /* @__PURE__ */ jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, className: "fixed inset-0 bg-black/50 flex items-center justify-center z-[9999]", onClick: () => setShowSavePresetModal(false), children: /* @__PURE__ */ jsxs(motion.div, { initial: { scale: 0.9, opacity: 0 }, animate: { scale: 1, opacity: 1 }, exit: { scale: 0.9, opacity: 0 }, onClick: (e) => e.stopPropagation(), className: "bg-background border rounded-lg p-6 w-96 shadow-2xl", children: [
769
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold mb-4", children: "Salvar Preset" }),
770
+ /* @__PURE__ */ jsx(
771
+ "input",
772
+ {
773
+ type: "text",
774
+ placeholder: "Nome do preset",
775
+ value: presetName,
776
+ onChange: (e) => setPresetName(e.target.value),
777
+ onKeyDown: (e) => e.key === "Enter" && confirmSavePreset(),
778
+ className: "w-full px-3 py-2 border border-input rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring mb-4",
779
+ autoFocus: true
780
+ }
781
+ ),
782
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 justify-end", children: [
783
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => {
784
+ setShowSavePresetModal(false);
785
+ setPresetName("");
786
+ }, children: "Cancelar" }),
787
+ /* @__PURE__ */ jsx(Button, { size: "sm", onClick: confirmSavePreset, disabled: !presetName.trim(), children: "Salvar" })
788
+ ] })
789
+ ] }) }) })
790
+ ] });
791
+ };
792
+ var SmartFilterPanel_default = SmartFilterPanel;
793
+ function DataTable({
794
+ data = [],
795
+ columns,
796
+ title,
797
+ subtitle,
798
+ icon: Icon,
799
+ loading = false,
800
+ total = 0,
801
+ page = 1,
802
+ pageSize = 25,
803
+ onPageChange,
804
+ onPageSizeChange,
805
+ search = "",
806
+ onSearchChange,
807
+ filters = [],
808
+ actions = [],
809
+ selectable = false,
810
+ selectedItems = [],
811
+ onSelectionChange,
812
+ onBulkDelete,
813
+ bulkDeleteLabel = "Excluir selecionados",
814
+ onRefresh,
815
+ onExport,
816
+ emptyMessage = "Nenhum registro encontrado",
817
+ emptyIcon: EmptyIcon,
818
+ stats = [],
819
+ enablePagination = true,
820
+ customActions,
821
+ sortBy,
822
+ sortOrder,
823
+ onSort,
824
+ hideHeader = false,
825
+ searchDebounce = true,
826
+ tableBodyHeight,
827
+ fillHeight = true,
828
+ onRowClick,
829
+ renderDrawer
830
+ }) {
831
+ const [drawerItem, setDrawerItem] = useState(null);
832
+ const [showBulkDeleteConfirm, setShowBulkDeleteConfirm] = useState(false);
833
+ const [isRefreshing, setIsRefreshing] = useState(false);
834
+ const [searchInput, setSearchInput] = useState(search);
835
+ const handleRowClick = (item) => {
836
+ if (renderDrawer) {
837
+ setDrawerItem(item);
838
+ return;
839
+ }
840
+ onRowClick?.(item);
841
+ };
842
+ React3__default.useEffect(() => {
843
+ setSearchInput(search);
844
+ }, [search]);
845
+ React3__default.useEffect(() => {
846
+ if (!searchDebounce) return;
847
+ const timer = setTimeout(() => {
848
+ if (onSearchChange && searchInput !== search) onSearchChange(searchInput);
849
+ }, 600);
850
+ return () => clearTimeout(timer);
851
+ }, [searchInput, searchDebounce]);
852
+ const handleSearchChange = (value) => {
853
+ if (searchDebounce) setSearchInput(value);
854
+ else onSearchChange?.(value);
855
+ };
856
+ const toggleSelectAll = () => {
857
+ const currentPageIds = data.map((item) => item.id);
858
+ const allCurrentSelected = currentPageIds.every((id) => selectedItems.includes(id));
859
+ if (allCurrentSelected) onSelectionChange?.(selectedItems.filter((id) => !currentPageIds.includes(id)));
860
+ else onSelectionChange?.([.../* @__PURE__ */ new Set([...selectedItems, ...currentPageIds])]);
861
+ };
862
+ const toggleSelectItem = (itemId) => {
863
+ if (selectedItems.includes(itemId)) onSelectionChange?.(selectedItems.filter((id) => id !== itemId));
864
+ else onSelectionChange?.([...selectedItems, itemId]);
865
+ };
866
+ if (loading) {
867
+ return /* @__PURE__ */ jsx("div", { className: "min-h-96 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
868
+ /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-16 w-16 border-b-2 border-primary mx-auto mb-4" }),
869
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Carregando dados..." })
870
+ ] }) });
871
+ }
872
+ const handleBulkDelete = () => {
873
+ if (onBulkDelete && selectedItems.length > 0) {
874
+ onBulkDelete(selectedItems);
875
+ setShowBulkDeleteConfirm(false);
876
+ }
877
+ };
878
+ return /* @__PURE__ */ jsxs("div", { className: fillHeight ? "flex flex-col h-full gap-4" : "space-y-4", children: [
879
+ /* @__PURE__ */ jsx(AnimatePresence, { children: selectable && selectedItems.length > 0 && /* @__PURE__ */ jsx(motion.div, { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: 20 }, className: "fixed bottom-6 left-1/2 -translate-x-1/2 z-50", children: /* @__PURE__ */ jsxs("div", { className: "bg-gradient-to-r from-slate-900 to-slate-800 dark:from-slate-800 dark:to-slate-900 text-white rounded-full shadow-2xl px-6 py-4 flex items-center gap-4 border border-slate-700", children: [
880
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
881
+ /* @__PURE__ */ jsx("div", { className: "w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-primary", children: selectedItems.length }) }),
882
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: selectedItems.length === 1 ? "1 item selecionado" : `${selectedItems.length} itens selecionados` })
883
+ ] }),
884
+ /* @__PURE__ */ jsx("div", { className: "h-6 w-px bg-slate-600" }),
885
+ onBulkDelete && /* @__PURE__ */ jsxs(Button, { onClick: () => setShowBulkDeleteConfirm(true), variant: "ghost", size: "sm", className: "text-red-400 hover:text-red-300 hover:bg-red-500/10 gap-2", children: [
886
+ /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" }),
887
+ bulkDeleteLabel
888
+ ] }),
889
+ /* @__PURE__ */ jsxs(Button, { onClick: () => onSelectionChange?.([]), variant: "ghost", size: "sm", className: "text-slate-400 hover:text-slate-300 hover:bg-slate-700 gap-2", children: [
890
+ /* @__PURE__ */ jsx(X, { className: "w-4 h-4" }),
891
+ "Cancelar"
892
+ ] })
893
+ ] }) }) }),
894
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showBulkDeleteConfirm && /* @__PURE__ */ jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, className: "fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4", onClick: () => setShowBulkDeleteConfirm(false), children: /* @__PURE__ */ jsxs(motion.div, { initial: { scale: 0.95, opacity: 0 }, animate: { scale: 1, opacity: 1 }, exit: { scale: 0.95, opacity: 0 }, onClick: (e) => e.stopPropagation(), className: "bg-background rounded-lg shadow-xl max-w-md w-full p-6 space-y-4", children: [
895
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
896
+ /* @__PURE__ */ jsx("div", { className: "w-12 h-12 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center", children: /* @__PURE__ */ jsx(Trash2, { className: "w-6 h-6 text-red-600 dark:text-red-400" }) }),
897
+ /* @__PURE__ */ jsxs("div", { children: [
898
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: "Confirmar Exclus\xE3o" }),
899
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
900
+ "Tem certeza que deseja excluir ",
901
+ selectedItems.length,
902
+ " ",
903
+ selectedItems.length === 1 ? "item" : "itens",
904
+ "?"
905
+ ] })
906
+ ] })
907
+ ] }),
908
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Esta a\xE7\xE3o n\xE3o pode ser desfeita." }),
909
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-3 justify-end", children: [
910
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setShowBulkDeleteConfirm(false), children: "Cancelar" }),
911
+ /* @__PURE__ */ jsxs(Button, { variant: "destructive", onClick: handleBulkDelete, className: "bg-red-600 hover:bg-red-700", children: [
912
+ /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4 mr-2" }),
913
+ "Excluir ",
914
+ selectedItems.length,
915
+ " ",
916
+ selectedItems.length === 1 ? "item" : "itens"
917
+ ] })
918
+ ] })
919
+ ] }) }) }),
920
+ !hideHeader && title && /* @__PURE__ */ jsx(
921
+ PageHeader,
922
+ {
923
+ title,
924
+ subtitle,
925
+ icon: Icon,
926
+ actions: /* @__PURE__ */ jsxs(Fragment, { children: [
927
+ onRefresh && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => {
928
+ setIsRefreshing(true);
929
+ onRefresh();
930
+ setTimeout(() => setIsRefreshing(false), 500);
931
+ }, children: [
932
+ /* @__PURE__ */ jsx(RefreshCw, { className: `w-4 h-4 mr-2 transition-transform ${isRefreshing ? "animate-[spin_0.5s_ease-in-out]" : ""}` }),
933
+ "Atualizar"
934
+ ] }),
935
+ onExport && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: onExport, children: [
936
+ /* @__PURE__ */ jsx(Download, { className: "w-4 h-4 mr-2" }),
937
+ "Exportar"
938
+ ] })
939
+ ] })
940
+ }
941
+ ),
942
+ stats && stats.length > 0 && /* @__PURE__ */ jsx("div", { className: `grid grid-cols-2 md:grid-cols-3 lg:grid-cols-${Math.min(stats.length, 6)} gap-4`, children: stats.map((stat, index) => /* @__PURE__ */ jsx(StatCard, { ...stat, variant: stat.variant || "slim" }, stat.label || index)) }),
943
+ (onSearchChange || filters.length > 0) && /* @__PURE__ */ jsx(
944
+ SmartFilterPanel_default,
945
+ {
946
+ filterGroups: filters.map((f) => ({
947
+ key: f.key,
948
+ label: f.label,
949
+ renderType: f.type === "select" ? "select" : "badges",
950
+ options: f.options?.map((opt) => {
951
+ const colorClasses = opt.color?.split(" ") || [];
952
+ const bgClass = colorClasses.find((c) => c.startsWith("bg-")) || "bg-slate-100";
953
+ const textClass = colorClasses.find((c) => c.startsWith("text-")) || "text-slate-800";
954
+ const borderClass = colorClasses.find((c) => c.startsWith("border-") && !c.includes("dark:")) || "border-slate-300";
955
+ const darkBgClass = colorClasses.find((c) => c.startsWith("dark:bg-")) || "dark:bg-slate-900/30";
956
+ const darkTextClass = colorClasses.find((c) => c.startsWith("dark:text-")) || "dark:text-slate-300";
957
+ const darkBorderClass = colorClasses.find((c) => c.startsWith("dark:border-")) || "dark:border-slate-800";
958
+ return { value: opt.value, label: opt.label, color: { bg: bgClass, text: textClass, border: borderClass, darkBg: darkBgClass, darkText: darkTextClass, darkBorder: darkBorderClass } };
959
+ }) || [],
960
+ selectedValues: Array.isArray(f.value) ? f.value : f.value ? [f.value] : [],
961
+ onChange: (values) => f.onChange(f.type === "select" ? values[0] || "" : values),
962
+ allLabel: f.type === "multiselect" ? "Todos" : void 0
963
+ })),
964
+ searchValue: searchDebounce ? searchInput : search,
965
+ onSearchChange: handleSearchChange,
966
+ searchPlaceholder: "Buscar...",
967
+ persistKey: title ? title.toLowerCase().replace(/\s+/g, "-") : "datatable"
968
+ }
969
+ ),
970
+ /* @__PURE__ */ jsxs(Card, { className: `shadow-lg ${fillHeight ? "flex flex-col flex-1 min-h-0" : ""}`, children: [
971
+ (title || customActions || selectable && selectedItems.length > 0) && /* @__PURE__ */ jsx(CardHeader, { className: `py-2 px-4 ${fillHeight ? "shrink-0" : ""}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
972
+ /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2 text-sm font-semibold", children: [
973
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5" }),
974
+ title,
975
+ /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "bg-primary/10 text-primary border-primary/20 text-[11px]", children: total || data.length })
976
+ ] }),
977
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
978
+ customActions,
979
+ selectable && selectedItems.length > 0 && /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "bg-blue-50 text-blue-700 border-blue-200 text-[11px]", children: [
980
+ selectedItems.length,
981
+ " selecionado",
982
+ selectedItems.length > 1 ? "s" : ""
983
+ ] })
984
+ ] })
985
+ ] }) }),
986
+ /* @__PURE__ */ jsxs(CardContent, { className: `p-0 overflow-hidden ${fillHeight ? "flex flex-col flex-1 min-h-0" : ""}`, children: [
987
+ /* @__PURE__ */ jsx("div", { className: `overflow-x-auto ${fillHeight ? "flex-1 min-h-0 overflow-y-auto" : ""}`, children: /* @__PURE__ */ jsx("div", { className: "w-full", style: tableBodyHeight ? { height: tableBodyHeight, overflowY: "auto" } : {}, children: /* @__PURE__ */ jsxs(Table2, { className: "w-full", children: [
988
+ /* @__PURE__ */ jsx(TableHeader, { className: "sticky top-0 z-10", children: /* @__PURE__ */ jsxs(TableRow, { className: "bg-muted/50", children: [
989
+ selectable && /* @__PURE__ */ jsx(TableHead, { className: "w-12", children: /* @__PURE__ */ jsx(Checkbox, { checked: data?.length > 0 && data.every((item) => selectedItems.includes(item.id)), onCheckedChange: toggleSelectAll }) }),
990
+ columns.map((column) => /* @__PURE__ */ jsx(
991
+ TableHead,
992
+ {
993
+ className: `${column.width} ${column.sortable && onSort ? "cursor-pointer hover:bg-muted/70 select-none" : ""}`,
994
+ onClick: () => column.sortable && onSort && onSort(String(column.key)),
995
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
996
+ column.label,
997
+ column.sortable && onSort && sortBy === String(column.key) && /* @__PURE__ */ jsx("span", { className: "text-xs", children: sortOrder === "asc" ? "\u2191" : "\u2193" })
998
+ ] })
999
+ },
1000
+ String(column.key)
1001
+ )),
1002
+ actions.length > 0 && /* @__PURE__ */ jsx(TableHead, { className: "w-16", children: "A\xE7\xF5es" })
1003
+ ] }) }),
1004
+ /* @__PURE__ */ jsx(TableBody, { children: /* @__PURE__ */ jsx(AnimatePresence, { children: data?.map((item, index) => /* @__PURE__ */ jsxs(
1005
+ motion.tr,
1006
+ {
1007
+ initial: { opacity: 0, y: 20 },
1008
+ animate: { opacity: 1, y: 0 },
1009
+ exit: { opacity: 0, y: -20 },
1010
+ transition: { delay: index * 0.05 },
1011
+ className: `hover:bg-muted/30 transition-colors ${onRowClick || renderDrawer ? "cursor-pointer" : ""}`,
1012
+ onClick: () => handleRowClick(item),
1013
+ children: [
1014
+ selectable && /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Checkbox, { checked: selectedItems.includes(item.id), onCheckedChange: () => toggleSelectItem(item.id) }) }),
1015
+ columns.map((column) => /* @__PURE__ */ jsx(TableCell, { onClick: column.key === "actions" ? (e) => e.stopPropagation() : void 0, children: column.render ? column.render(item, index) : String(item[column.key] || "") }, String(column.key))),
1016
+ actions.length > 0 && /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: actions.filter((action) => !action.condition || action.condition(item)).map((action, actionIndex) => {
1017
+ const label = typeof action.label === "function" ? action.label(item) : action.label;
1018
+ const className = typeof action.className === "function" ? action.className(item) : action.className;
1019
+ return /* @__PURE__ */ jsx(Button, { variant: action.variant || "ghost", size: "sm", onClick: () => action.onClick(item), title: label, className, children: /* @__PURE__ */ jsx(action.icon, { className: "w-4 h-4" }) }, actionIndex);
1020
+ }) }) })
1021
+ ]
1022
+ },
1023
+ `${item.id}-${index}`
1024
+ )) }) })
1025
+ ] }) }) }),
1026
+ (!data || data.length === 0) && /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
1027
+ EmptyIcon && /* @__PURE__ */ jsx(EmptyIcon, { className: "w-10 h-10 text-muted-foreground mx-auto mb-3" }),
1028
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage })
1029
+ ] })
1030
+ ] }),
1031
+ enablePagination && total > 0 && onPageChange && /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-2 px-4 py-2 border-t bg-muted/20", children: [
1032
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-xs text-muted-foreground", children: [
1033
+ /* @__PURE__ */ jsxs("span", { children: [
1034
+ "Mostrando ",
1035
+ (page - 1) * pageSize + 1,
1036
+ "\u2013",
1037
+ Math.min(page * pageSize, total),
1038
+ " de ",
1039
+ total
1040
+ ] }),
1041
+ onPageSizeChange && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
1042
+ /* @__PURE__ */ jsx("span", { children: "Por p\xE1gina:" }),
1043
+ /* @__PURE__ */ jsxs("select", { value: pageSize, onChange: (e) => onPageSizeChange(Number(e.target.value)), className: "px-1.5 py-0.5 border border-border rounded text-xs bg-background", children: [
1044
+ /* @__PURE__ */ jsx("option", { value: 10, children: "10" }),
1045
+ /* @__PURE__ */ jsx("option", { value: 25, children: "25" }),
1046
+ /* @__PURE__ */ jsx("option", { value: 50, children: "50" }),
1047
+ /* @__PURE__ */ jsx("option", { value: 100, children: "100" })
1048
+ ] })
1049
+ ] })
1050
+ ] }),
1051
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1052
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => onPageChange(1), disabled: page === 1, className: "hidden sm:flex h-7 text-xs px-2", children: "Primeira" }),
1053
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => onPageChange(page - 1), disabled: page === 1, className: "h-7 text-xs px-2", children: "\u2039 Anterior" }),
1054
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: Array.from({ length: Math.min(5, Math.ceil(total / pageSize)) }, (_, i) => {
1055
+ const totalPages = Math.ceil(total / pageSize);
1056
+ let pageNum;
1057
+ if (totalPages <= 5) pageNum = i + 1;
1058
+ else if (page <= 3) pageNum = i + 1;
1059
+ else if (page >= totalPages - 2) pageNum = totalPages - 4 + i;
1060
+ else pageNum = page - 2 + i;
1061
+ return /* @__PURE__ */ jsx(Button, { variant: page === pageNum ? "default" : "outline", size: "sm", onClick: () => onPageChange(pageNum), className: "w-7 h-7 p-0 text-xs", children: pageNum }, pageNum);
1062
+ }) }),
1063
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => onPageChange(page + 1), disabled: page >= Math.ceil(total / pageSize), className: "h-7 text-xs px-2", children: "Pr\xF3xima \u203A" }),
1064
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => onPageChange(Math.ceil(total / pageSize)), disabled: page >= Math.ceil(total / pageSize), className: "hidden sm:flex h-7 text-xs px-2", children: "\xDAltima" })
1065
+ ] })
1066
+ ] })
1067
+ ] }),
1068
+ renderDrawer && drawerItem && renderDrawer(drawerItem, () => setDrawerItem(null))
1069
+ ] });
1070
+ }
1071
+ var DataTable_default = DataTable;
1072
+ var Toast = ({ message, type, onClose, duration = 4e3, entity, action }) => {
1073
+ const [isVisible, setIsVisible] = useState(false);
1074
+ const [progress, setProgress] = useState(100);
1075
+ const getAutoMessage = () => {
1076
+ if (message) return message;
1077
+ if (!entity || !action) return "Opera\xE7\xE3o realizada";
1078
+ const messages = {
1079
+ created: `${entity} criado com sucesso!`,
1080
+ updated: `${entity} atualizado com sucesso!`,
1081
+ deleted: `${entity} removido com sucesso!`,
1082
+ error: `Erro ao processar ${entity.toLowerCase()}`
1083
+ };
1084
+ return messages[action] || "Opera\xE7\xE3o realizada";
1085
+ };
1086
+ useEffect(() => {
1087
+ setIsVisible(true);
1088
+ const progressInterval = setInterval(() => {
1089
+ setProgress((prev) => Math.max(0, prev - 100 / (duration / 100)));
1090
+ }, 100);
1091
+ const timer = setTimeout(() => {
1092
+ setIsVisible(false);
1093
+ setTimeout(onClose, 300);
1094
+ }, duration);
1095
+ return () => {
1096
+ clearTimeout(timer);
1097
+ clearInterval(progressInterval);
1098
+ };
1099
+ }, [duration, onClose]);
1100
+ const handleClose = () => {
1101
+ setIsVisible(false);
1102
+ setTimeout(onClose, 300);
1103
+ };
1104
+ const config = {
1105
+ success: { bg: "bg-gradient-to-r from-emerald-500 to-green-600", icon: CheckCircle, shadow: "shadow-emerald-500/25" },
1106
+ error: { bg: "bg-gradient-to-r from-red-500 to-rose-600", icon: AlertTriangle, shadow: "shadow-red-500/25" }
1107
+ };
1108
+ const { bg, icon: Icon, shadow } = config[type];
1109
+ return createPortal(
1110
+ /* @__PURE__ */ jsx("div", { className: "fixed top-24 right-6 z-[9999]", children: /* @__PURE__ */ jsxs("div", { className: `${bg} ${shadow} min-w-80 max-w-md p-4 rounded-2xl shadow-2xl backdrop-blur-sm transform transition-all duration-300 ease-out ${isVisible ? "translate-x-0 opacity-100 scale-100" : "translate-x-full opacity-0 scale-95"}`, children: [
1111
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
1112
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 bg-white/20 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx(Icon, { className: "w-4 h-4 text-white" }) }) }),
1113
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("p", { className: "text-white font-medium text-sm leading-relaxed", children: getAutoMessage() }) }),
1114
+ /* @__PURE__ */ jsx("button", { onClick: handleClose, className: "flex-shrink-0 text-white/70 hover:text-white transition-colors p-1 hover:bg-white/10 rounded-full", children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" }) })
1115
+ ] }),
1116
+ /* @__PURE__ */ jsx("div", { className: "mt-3 h-1 bg-white/20 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "h-full bg-white/40 rounded-full transition-all duration-100 ease-linear", style: { width: `${progress}%` } }) })
1117
+ ] }) }),
1118
+ document.body
1119
+ );
1120
+ };
1121
+ var Toast_default = Toast;
1122
+ function Dialog({ open, onOpenChange, children }) {
1123
+ useEffect(() => {
1124
+ if (open) {
1125
+ const scrollY = window.scrollY;
1126
+ document.body.style.position = "fixed";
1127
+ document.body.style.top = `-${scrollY}px`;
1128
+ document.body.style.width = "100%";
1129
+ document.body.classList.add("modal-open");
1130
+ } else {
1131
+ const scrollY = document.body.style.top;
1132
+ document.body.style.position = "";
1133
+ document.body.style.top = "";
1134
+ document.body.style.width = "";
1135
+ document.body.classList.remove("modal-open");
1136
+ if (scrollY) {
1137
+ window.scrollTo(0, parseInt(scrollY || "0") * -1);
1138
+ }
1139
+ }
1140
+ return () => {
1141
+ document.body.style.position = "";
1142
+ document.body.style.top = "";
1143
+ document.body.style.width = "";
1144
+ document.body.classList.remove("modal-open");
1145
+ };
1146
+ }, [open]);
1147
+ if (!open) return null;
1148
+ const handleBackdropClick = (e) => {
1149
+ if (e.target === e.currentTarget) onOpenChange(false);
1150
+ };
1151
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", onClick: handleBackdropClick, children: [
1152
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/60 backdrop-blur-sm transition-all duration-300" }),
1153
+ /* @__PURE__ */ jsx("div", { className: "relative z-50 animate-in fade-in-0 zoom-in-95 duration-300", children })
1154
+ ] });
1155
+ }
1156
+ var DialogContent = forwardRef(
1157
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
1158
+ "div",
1159
+ {
1160
+ ref,
1161
+ className: cn(
1162
+ "bg-card/95 backdrop-blur-none border border-border/50 rounded-2xl shadow-2xl w-full p-0 max-h-[90vh] overflow-y-auto",
1163
+ className
1164
+ ),
1165
+ onClick: (e) => e.stopPropagation(),
1166
+ onWheel: (e) => e.stopPropagation(),
1167
+ ...props,
1168
+ children
1169
+ }
1170
+ )
1171
+ );
1172
+ DialogContent.displayName = "DialogContent";
1173
+ function DialogHeader({ className, children }) {
1174
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-1.5 p-6 pb-4 border-b border-border/30", className), children });
1175
+ }
1176
+ function DialogTitle({ className, children }) {
1177
+ return /* @__PURE__ */ jsx("h2", { className: cn("text-xl font-semibold text-foreground leading-none tracking-tight", className), children });
1178
+ }
1179
+ function DialogDescription({ children }) {
1180
+ return /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children });
1181
+ }
1182
+ function DialogFooter({ children }) {
1183
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 p-6 pt-4", children });
1184
+ }
1185
+ function DialogTrigger({ asChild, children, onClick }) {
1186
+ if (asChild) {
1187
+ const child = children;
1188
+ return React3__default.cloneElement(child, {
1189
+ onClick: (e) => {
1190
+ if (child.props.onClick) child.props.onClick(e);
1191
+ if (onClick) onClick();
1192
+ }
1193
+ });
1194
+ }
1195
+ return /* @__PURE__ */ jsx("button", { onClick, children });
1196
+ }
1197
+ var Input = React3.forwardRef(
1198
+ ({ className, type, ...props }, ref) => {
1199
+ return /* @__PURE__ */ jsx(
1200
+ "input",
1201
+ {
1202
+ type,
1203
+ className: cn(
1204
+ "flex h-9 w-full rounded-md border border-input bg-[hsl(var(--input-bg))] px-3 py-2 text-xs text-foreground ring-offset-background file:border-0 file:bg-transparent file:text-xs file:font-medium placeholder:text-muted-foreground/50 focus-visible:outline-none focus-visible:border-primary/60 focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50 transition-colors duration-150",
1205
+ className
1206
+ ),
1207
+ ref,
1208
+ ...props
1209
+ }
1210
+ );
1211
+ }
1212
+ );
1213
+ Input.displayName = "Input";
1214
+ var ConfirmDialog = ({
1215
+ isOpen,
1216
+ onClose,
1217
+ onConfirm,
1218
+ title,
1219
+ message,
1220
+ type = "warning",
1221
+ confirmText,
1222
+ cancelText = "Cancelar",
1223
+ loading = false,
1224
+ requireConfirmation = false,
1225
+ confirmationText = "CONFIRMAR",
1226
+ details = [],
1227
+ impact
1228
+ }) => {
1229
+ const [confirmationInput, setConfirmationInput] = useState("");
1230
+ const [showDetails, setShowDetails] = useState(false);
1231
+ const isConfirmationValid = !requireConfirmation || confirmationInput.toUpperCase() === confirmationText.toUpperCase();
1232
+ const handleClose = () => {
1233
+ setConfirmationInput("");
1234
+ setShowDetails(false);
1235
+ onClose();
1236
+ };
1237
+ const handleConfirm = () => {
1238
+ if (isConfirmationValid) {
1239
+ onConfirm();
1240
+ setConfirmationInput("");
1241
+ }
1242
+ };
1243
+ const getConfig = () => {
1244
+ switch (type) {
1245
+ case "delete":
1246
+ return { icon: /* @__PURE__ */ jsx(Trash2, { className: "w-6 h-6 text-red-500" }), confirmText: confirmText || "Excluir", confirmVariant: "destructive", bgColor: "bg-gradient-to-br from-red-50 to-red-100 dark:from-red-950/30 dark:to-red-900/20", borderColor: "border-red-200 dark:border-red-800" };
1247
+ case "danger":
1248
+ return { icon: /* @__PURE__ */ jsx(Shield, { className: "w-6 h-6 text-red-600" }), confirmText: confirmText || "Executar", confirmVariant: "destructive", bgColor: "bg-gradient-to-br from-red-100 to-red-200 dark:from-red-950/50 dark:to-red-900/30", borderColor: "border-red-300 dark:border-red-700" };
1249
+ case "edit":
1250
+ return { icon: /* @__PURE__ */ jsx(Edit, { className: "w-6 h-6 text-blue-500" }), confirmText: confirmText || "Confirmar", confirmVariant: "default", bgColor: "bg-gradient-to-br from-blue-50 to-blue-100 dark:from-blue-950/30 dark:to-blue-900/20", borderColor: "border-blue-200 dark:border-blue-800" };
1251
+ case "create":
1252
+ return { icon: /* @__PURE__ */ jsx(Plus, { className: "w-6 h-6 text-green-500" }), confirmText: confirmText || "Criar", confirmVariant: "default", bgColor: "bg-gradient-to-br from-green-50 to-green-100 dark:from-green-950/30 dark:to-green-900/20", borderColor: "border-green-200 dark:border-green-800" };
1253
+ default:
1254
+ return { icon: /* @__PURE__ */ jsx(AlertTriangle, { className: "w-6 h-6 text-yellow-500" }), confirmText: confirmText || "Confirmar", confirmVariant: "default", bgColor: "bg-gradient-to-br from-yellow-50 to-yellow-100 dark:from-yellow-950/30 dark:to-yellow-900/20", borderColor: "border-yellow-200 dark:border-yellow-800" };
1255
+ }
1256
+ };
1257
+ const config = getConfig();
1258
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: onClose, children: /* @__PURE__ */ jsx(DialogContent, { className: "max-w-md mx-auto p-0 overflow-hidden border-0 shadow-2xl", children: /* @__PURE__ */ jsxs(motion.div, { initial: { scale: 0.95, opacity: 0 }, animate: { scale: 1, opacity: 1 }, exit: { scale: 0.95, opacity: 0 }, transition: { duration: 0.2, ease: "easeOut" }, className: "relative", children: [
1259
+ /* @__PURE__ */ jsxs("div", { className: `${config.bgColor} ${config.borderColor} px-6 py-8 text-center relative overflow-hidden`, children: [
1260
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-white/20 to-transparent" }),
1261
+ /* @__PURE__ */ jsxs("div", { className: "relative z-10", children: [
1262
+ /* @__PURE__ */ jsx(motion.div, { initial: { scale: 0 }, animate: { scale: 1 }, transition: { delay: 0.1, type: "spring", stiffness: 200 }, className: "w-16 h-16 mx-auto mb-4 rounded-full bg-white/90 backdrop-blur-sm flex items-center justify-center shadow-lg", children: /* @__PURE__ */ jsx("div", { className: "scale-150", children: config.icon }) }),
1263
+ /* @__PURE__ */ jsx(motion.h2, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.2 }, className: "text-xl font-bold text-gray-900 dark:text-white mb-2 drop-shadow-sm", children: title })
1264
+ ] })
1265
+ ] }),
1266
+ /* @__PURE__ */ jsxs("div", { className: "px-6 py-6 bg-white dark:bg-gray-900 space-y-4", children: [
1267
+ /* @__PURE__ */ jsx(motion.div, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.3 }, className: "text-center text-gray-700 dark:text-gray-200 leading-relaxed font-medium", children: message.split("\n").map((line, index) => /* @__PURE__ */ jsx("p", { className: index > 0 ? "mt-2" : "", children: line }, index)) }),
1268
+ impact && /* @__PURE__ */ jsx(motion.div, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.4 }, className: "bg-orange-50 dark:bg-orange-950/30 border border-orange-200 dark:border-orange-800 rounded-lg p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
1269
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "w-5 h-5 text-orange-500 mt-0.5 flex-shrink-0" }),
1270
+ /* @__PURE__ */ jsxs("div", { children: [
1271
+ /* @__PURE__ */ jsx("p", { className: "font-medium text-orange-800 dark:text-orange-200 mb-1", children: "Impacto da Opera\xE7\xE3o:" }),
1272
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-orange-700 dark:text-orange-300", children: impact })
1273
+ ] })
1274
+ ] }) }),
1275
+ details.length > 0 && /* @__PURE__ */ jsxs(motion.div, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.5 }, className: "space-y-2", children: [
1276
+ /* @__PURE__ */ jsxs("button", { onClick: () => setShowDetails(!showDetails), className: "text-sm text-blue-600 dark:text-blue-400 hover:underline flex items-center gap-1", children: [
1277
+ /* @__PURE__ */ jsx(Database, { className: "w-4 h-4" }),
1278
+ showDetails ? "Ocultar detalhes" : "Ver detalhes"
1279
+ ] }),
1280
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showDetails && /* @__PURE__ */ jsx(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, className: "bg-gray-50 dark:bg-gray-800 rounded-lg p-3 overflow-hidden", children: /* @__PURE__ */ jsx("ul", { className: "text-sm text-gray-600 dark:text-gray-300 space-y-1", children: details.map((detail, index) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2", children: [
1281
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400 mt-1", children: "\u2022" }),
1282
+ /* @__PURE__ */ jsx("span", { children: detail })
1283
+ ] }, index)) }) }) })
1284
+ ] }),
1285
+ requireConfirmation && /* @__PURE__ */ jsx(motion.div, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.6 }, className: "space-y-3", children: /* @__PURE__ */ jsxs("div", { className: "bg-red-50 dark:bg-red-950/30 border border-red-200 dark:border-red-800 rounded-lg p-4", children: [
1286
+ /* @__PURE__ */ jsxs("p", { className: "text-sm font-medium text-red-800 dark:text-red-200 mb-2", children: [
1287
+ "Para confirmar, digite: ",
1288
+ /* @__PURE__ */ jsx("code", { className: "bg-red-100 dark:bg-red-900 px-2 py-1 rounded text-red-900 dark:text-red-100", children: confirmationText })
1289
+ ] }),
1290
+ /* @__PURE__ */ jsx(Input, { value: confirmationInput, onChange: (e) => setConfirmationInput(e.target.value), placeholder: `Digite "${confirmationText}" para confirmar`, className: `${!isConfirmationValid && confirmationInput ? "border-red-300 focus:border-red-500" : ""}`, disabled: loading })
1291
+ ] }) })
1292
+ ] }),
1293
+ /* @__PURE__ */ jsxs(motion.div, { initial: { y: 20, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.4 }, className: "px-6 py-4 bg-gray-50 dark:bg-gray-800 flex gap-3 justify-center", children: [
1294
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, disabled: loading, className: "min-w-24", children: cancelText }),
1295
+ /* @__PURE__ */ jsx(Button, { variant: config.confirmVariant, onClick: handleConfirm, disabled: loading || !isConfirmationValid, className: `min-w-24 shadow-lg ${!isConfirmationValid ? "opacity-50 cursor-not-allowed" : ""}`, children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
1296
+ /* @__PURE__ */ jsx("div", { className: "w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin mr-2" }),
1297
+ "Processando..."
1298
+ ] }) : config.confirmText })
1299
+ ] }),
1300
+ /* @__PURE__ */ jsx("button", { onClick: handleClose, disabled: loading, className: "absolute top-4 right-4 w-8 h-8 rounded-full bg-white/90 backdrop-blur-sm hover:bg-white transition-colors flex items-center justify-center shadow-md z-20 disabled:opacity-50 disabled:cursor-not-allowed", children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4 text-gray-800" }) })
1301
+ ] }) }) }) });
1302
+ };
1303
+ var ConfirmDialog_default = ConfirmDialog;
1304
+ function CardView({
1305
+ queryKey,
1306
+ queryFn,
1307
+ title,
1308
+ subtitle,
1309
+ icon: Icon,
1310
+ hideHeader = false,
1311
+ emptyMessage = "Nenhum registro encontrado",
1312
+ emptyIcon: EmptyIcon,
1313
+ renderCard,
1314
+ onCardClick,
1315
+ selectedItem: externalSelectedItem,
1316
+ onSelectedItemChange,
1317
+ stats,
1318
+ filters,
1319
+ filterFn,
1320
+ activeFilters: externalActiveFilters,
1321
+ onActiveFiltersChange,
1322
+ searchPlaceholder = "Buscar...",
1323
+ searchColumns = [],
1324
+ persistKey,
1325
+ enablePresets,
1326
+ enableHistory,
1327
+ enableUrlSync,
1328
+ onNew,
1329
+ newButtonLabel = "Novo",
1330
+ onExport,
1331
+ renderDrawer,
1332
+ deleteFn,
1333
+ deleteTitle = "Confirmar exclus\xE3o",
1334
+ deleteMessage = () => "Tem certeza que deseja excluir este registro?",
1335
+ renderAdvancedFilters
1336
+ }) {
1337
+ const queryClient = useQueryClient();
1338
+ const [internalSelectedItem, setInternalSelectedItem] = useState(null);
1339
+ const selectedItem = externalSelectedItem !== void 0 ? externalSelectedItem : internalSelectedItem;
1340
+ const setSelectedItem = onSelectedItemChange || setInternalSelectedItem;
1341
+ const [searchTerm, setSearchTerm] = useState("");
1342
+ const [internalActiveFilters, setInternalActiveFilters] = useState([]);
1343
+ const activeFilters = externalActiveFilters !== void 0 ? externalActiveFilters : internalActiveFilters;
1344
+ const setActiveFilters = onActiveFiltersChange || setInternalActiveFilters;
1345
+ const [showFilters, setShowFilters] = useState(false);
1346
+ const [deleteItemId, setDeleteItemId] = useState(null);
1347
+ const [toastState, setToastState] = useState(null);
1348
+ const { data: response, isLoading } = useQuery({ queryKey, queryFn });
1349
+ const items = Array.isArray(response) ? response : response?.data || response?.assets || [];
1350
+ const computedStats = typeof stats === "function" ? stats(items) : stats;
1351
+ const computedFilters = typeof filters === "function" ? filters(items) : filters;
1352
+ const deleteMutation = useMutation({
1353
+ mutationFn: (id) => deleteFn(id),
1354
+ onSuccess: () => {
1355
+ queryClient.invalidateQueries({ queryKey });
1356
+ setToastState({ message: "Registro exclu\xEDdo com sucesso", type: "success" });
1357
+ setSelectedItem(null);
1358
+ setDeleteItemId(null);
1359
+ },
1360
+ onError: (error) => {
1361
+ setToastState({ message: error.response?.data?.message || "N\xE3o foi poss\xEDvel excluir o registro", type: "error" });
1362
+ }
1363
+ });
1364
+ const handleDelete = (id) => setDeleteItemId(id);
1365
+ const confirmDelete = () => {
1366
+ if (deleteItemId && deleteFn) deleteMutation.mutate(deleteItemId);
1367
+ };
1368
+ const filteredItems = items.filter((item) => {
1369
+ const matchesSearch = searchColumns.length === 0 || searchColumns.some((col) => {
1370
+ const value = item[col.key];
1371
+ return value && String(value).toLowerCase().includes(searchTerm.toLowerCase());
1372
+ });
1373
+ const matchesFilter = !filterFn || activeFilters.length === 0 || activeFilters.some((filterValue) => filterFn(item, filterValue));
1374
+ return matchesSearch && matchesFilter;
1375
+ });
1376
+ const DisplayIcon = EmptyIcon || Icon;
1377
+ const colorMap = {
1378
+ green: { bg: "bg-green-100", text: "text-green-800", border: "border-green-300", darkBg: "dark:bg-green-900/30", darkText: "dark:text-green-300", darkBorder: "dark:border-green-800" },
1379
+ red: { bg: "bg-red-100", text: "text-red-800", border: "border-red-300", darkBg: "dark:bg-red-900/30", darkText: "dark:text-red-300", darkBorder: "dark:border-red-800" },
1380
+ blue: { bg: "bg-blue-100", text: "text-blue-800", border: "border-blue-300", darkBg: "dark:bg-blue-900/30", darkText: "dark:text-blue-300", darkBorder: "dark:border-blue-800" },
1381
+ cyan: { bg: "bg-cyan-100", text: "text-cyan-800", border: "border-cyan-300", darkBg: "dark:bg-cyan-900/30", darkText: "dark:text-cyan-300", darkBorder: "dark:border-cyan-800" },
1382
+ orange: { bg: "bg-orange-100", text: "text-orange-800", border: "border-orange-300", darkBg: "dark:bg-orange-900/30", darkText: "dark:text-orange-300", darkBorder: "dark:border-orange-800" },
1383
+ gray: { bg: "bg-slate-100", text: "text-slate-800", border: "border-slate-300", darkBg: "dark:bg-slate-900/30", darkText: "dark:text-slate-300", darkBorder: "dark:border-slate-800" },
1384
+ purple: { bg: "bg-purple-100", text: "text-purple-800", border: "border-purple-300", darkBg: "dark:bg-purple-900/30", darkText: "dark:text-purple-300", darkBorder: "dark:border-purple-800" }
1385
+ };
1386
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
1387
+ !hideHeader && title && Icon && /* @__PURE__ */ jsx(
1388
+ PageHeader,
1389
+ {
1390
+ title,
1391
+ subtitle,
1392
+ icon: Icon,
1393
+ actions: /* @__PURE__ */ jsxs(Fragment, { children: [
1394
+ onExport && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: onExport, children: [
1395
+ /* @__PURE__ */ jsx(Download, { className: "h-4 w-4 mr-2" }),
1396
+ "Exportar"
1397
+ ] }),
1398
+ onNew && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: onNew, children: [
1399
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
1400
+ newButtonLabel
1401
+ ] })
1402
+ ] })
1403
+ }
1404
+ ),
1405
+ computedStats && computedStats.length > 0 && /* @__PURE__ */ jsx("div", { className: `grid grid-cols-2 md:grid-cols-3 lg:grid-cols-${Math.min(computedStats.length, 6)} gap-4`, children: computedStats.map((stat, idx) => /* @__PURE__ */ jsx(StatCard, { ...stat }, stat.label || idx)) }),
1406
+ computedFilters && computedFilters.length > 0 && /* @__PURE__ */ jsx(
1407
+ SmartFilterPanel_default,
1408
+ {
1409
+ filterGroups: [{
1410
+ key: "status",
1411
+ label: "Status",
1412
+ renderType: "badges",
1413
+ allLabel: "Todos",
1414
+ options: computedFilters.map((f) => ({
1415
+ value: f.value,
1416
+ label: f.label,
1417
+ emoji: f.emoji,
1418
+ color: colorMap[f.color || "gray"] || colorMap.gray
1419
+ })),
1420
+ selectedValues: activeFilters,
1421
+ onChange: setActiveFilters
1422
+ }],
1423
+ searchValue: searchTerm,
1424
+ onSearchChange: setSearchTerm,
1425
+ searchPlaceholder,
1426
+ resultsCount: filteredItems.length,
1427
+ persistKey,
1428
+ enablePresets,
1429
+ enableHistory,
1430
+ enableUrlSync,
1431
+ onClearAll: () => {
1432
+ setSearchTerm("");
1433
+ setActiveFilters([]);
1434
+ }
1435
+ }
1436
+ ),
1437
+ /* @__PURE__ */ jsx("div", { children: isLoading ? /* @__PURE__ */ jsxs("div", { className: "text-center py-12 text-muted-foreground", children: [
1438
+ DisplayIcon && /* @__PURE__ */ jsx(DisplayIcon, { className: "w-16 h-16 mx-auto mb-4 opacity-30 animate-pulse" }),
1439
+ /* @__PURE__ */ jsx("p", { children: "Carregando..." })
1440
+ ] }) : filteredItems.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-12 text-muted-foreground", children: [
1441
+ DisplayIcon && /* @__PURE__ */ jsx(DisplayIcon, { className: "w-16 h-16 mx-auto mb-4 opacity-30" }),
1442
+ /* @__PURE__ */ jsx("p", { className: "font-medium", children: emptyMessage }),
1443
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: "Tente ajustar os filtros ou adicione um novo registro" })
1444
+ ] }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-4", children: filteredItems.map((item, index) => /* @__PURE__ */ jsx(
1445
+ motion.div,
1446
+ {
1447
+ initial: { opacity: 0, y: 20 },
1448
+ animate: { opacity: 1, y: 0 },
1449
+ transition: { delay: index * 0.05, duration: 0.3 },
1450
+ onClick: () => {
1451
+ onCardClick(item);
1452
+ setSelectedItem(item);
1453
+ },
1454
+ className: "cursor-pointer",
1455
+ children: renderCard(item, selectedItem?.id === item.id, deleteFn ? handleDelete : void 0)
1456
+ },
1457
+ `${item.id}-${index}`
1458
+ )) }) }),
1459
+ selectedItem && renderDrawer && /* @__PURE__ */ jsxs(Fragment, { children: [
1460
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/20 dark:bg-black/40 z-40", onClick: () => setSelectedItem(null) }),
1461
+ renderDrawer(selectedItem, () => setSelectedItem(null), () => {
1462
+ }, handleDelete)
1463
+ ] }),
1464
+ renderAdvancedFilters && renderAdvancedFilters(showFilters, setShowFilters),
1465
+ deleteFn && /* @__PURE__ */ jsx(
1466
+ ConfirmDialog_default,
1467
+ {
1468
+ isOpen: deleteItemId !== null,
1469
+ onClose: () => setDeleteItemId(null),
1470
+ onConfirm: confirmDelete,
1471
+ type: "delete",
1472
+ title: deleteTitle,
1473
+ message: deleteItemId ? deleteMessage(items.find((i) => i.id === deleteItemId)) : "",
1474
+ loading: deleteMutation.isPending
1475
+ }
1476
+ ),
1477
+ toastState && /* @__PURE__ */ jsx(Toast_default, { message: toastState.message, type: toastState.type, onClose: () => setToastState(null) })
1478
+ ] });
1479
+ }
1480
+
1481
+ // src/theme/tokens.ts
1482
+ var defaultTheme = {
1483
+ background: "210 20% 96%",
1484
+ foreground: "240 10% 4%",
1485
+ card: "0 0% 100%",
1486
+ cardForeground: "240 10% 4%",
1487
+ primary: "142 76% 36%",
1488
+ primaryForeground: "0 0% 100%",
1489
+ secondary: "240 5% 96%",
1490
+ secondaryForeground: "240 10% 4%",
1491
+ muted: "240 5% 96%",
1492
+ mutedForeground: "240 4% 46%",
1493
+ accent: "217 91% 60%",
1494
+ accentForeground: "0 0% 100%",
1495
+ destructive: "0 72% 51%",
1496
+ destructiveForeground: "0 0% 100%",
1497
+ border: "240 6% 90%",
1498
+ input: "240 6% 90%",
1499
+ inputBg: "0 0% 100%",
1500
+ ring: "142 76% 36%",
1501
+ radius: "0.75rem"
1502
+ };
1503
+ var defaultDarkTheme = {
1504
+ background: "222 47% 8%",
1505
+ foreground: "210 40% 98%",
1506
+ card: "222 47% 15%",
1507
+ cardForeground: "210 40% 98%",
1508
+ primary: "161 94% 43%",
1509
+ primaryForeground: "255 100% 100%",
1510
+ secondary: "215 28% 21%",
1511
+ secondaryForeground: "210 40% 98%",
1512
+ muted: "215 28% 21%",
1513
+ mutedForeground: "215 20% 65%",
1514
+ accent: "161 94% 43%",
1515
+ accentForeground: "255 100% 100%",
1516
+ destructive: "0 84% 60%",
1517
+ destructiveForeground: "210 40% 98%",
1518
+ border: "215 28% 21%",
1519
+ input: "215 28% 21%",
1520
+ inputBg: "215 28% 17%",
1521
+ ring: "161 94% 43%"
1522
+ };
1523
+ function applyTheme(tokens, selector) {
1524
+ const map = {
1525
+ background: "--background",
1526
+ foreground: "--foreground",
1527
+ card: "--card",
1528
+ cardForeground: "--card-foreground",
1529
+ primary: "--primary",
1530
+ primaryForeground: "--primary-foreground",
1531
+ secondary: "--secondary",
1532
+ secondaryForeground: "--secondary-foreground",
1533
+ muted: "--muted",
1534
+ mutedForeground: "--muted-foreground",
1535
+ accent: "--accent",
1536
+ accentForeground: "--accent-foreground",
1537
+ destructive: "--destructive",
1538
+ destructiveForeground: "--destructive-foreground",
1539
+ border: "--border",
1540
+ input: "--input",
1541
+ inputBg: "--input-bg",
1542
+ ring: "--ring",
1543
+ radius: "--radius"
1544
+ };
1545
+ const el = document.documentElement ;
1546
+ if (!el) return;
1547
+ Object.entries(tokens).forEach(([key, value]) => {
1548
+ if (value !== void 0) el.style.setProperty(map[key], value);
1549
+ });
1550
+ }
1551
+ function ThemeProvider({ children, theme, darkTheme }) {
1552
+ useEffect(() => {
1553
+ const light = { ...defaultTheme, ...theme };
1554
+ applyTheme(light);
1555
+ }, [theme]);
1556
+ useEffect(() => {
1557
+ const dark = { ...defaultDarkTheme, ...darkTheme };
1558
+ const applyDark = () => {
1559
+ if (document.documentElement.classList.contains("dark")) {
1560
+ applyTheme(dark);
1561
+ } else {
1562
+ const light = { ...defaultTheme, ...theme };
1563
+ applyTheme(light);
1564
+ }
1565
+ };
1566
+ applyDark();
1567
+ const observer = new MutationObserver(applyDark);
1568
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
1569
+ return () => observer.disconnect();
1570
+ }, [theme, darkTheme]);
1571
+ return /* @__PURE__ */ jsx(Fragment, { children });
1572
+ }
1573
+
1574
+ export { Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardView, Checkbox, ConfirmDialog_default as ConfirmDialog, DataTable_default as DataTable, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Input, PageHeader, PageLayout, STAT_ACCENT_SEQUENCE, SmartFilterPanel_default as SmartFilterPanel, StatCard, Table2 as Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, ThemeProvider, Toast_default as Toast, badgeVariants, buttonVariants, cn, defaultDarkTheme, defaultTheme };
1575
+ //# sourceMappingURL=index.js.map
1576
+ //# sourceMappingURL=index.js.map