@classytic/fluid 0.2.4 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -62
  3. package/dist/api-pagination-CJ0vR_w6.d.mts +34 -0
  4. package/dist/api-pagination-DBTE0yk4.mjs +190 -0
  5. package/dist/chunk-DQk6qfdC.mjs +18 -0
  6. package/dist/client/calendar.d.mts +105 -0
  7. package/dist/client/calendar.mjs +202 -0
  8. package/dist/client/core.d.mts +1614 -0
  9. package/dist/client/core.mjs +2779 -0
  10. package/dist/client/error.d.mts +125 -0
  11. package/dist/client/error.mjs +166 -0
  12. package/dist/client/hooks.d.mts +162 -0
  13. package/dist/client/hooks.mjs +447 -0
  14. package/dist/client/table.d.mts +84 -0
  15. package/dist/client/table.mjs +373 -0
  16. package/dist/client/theme.d.mts +6 -0
  17. package/dist/client/theme.mjs +65 -0
  18. package/dist/command.d.mts +134 -0
  19. package/dist/command.mjs +132 -0
  20. package/dist/compact.d.mts +359 -0
  21. package/dist/compact.mjs +892 -0
  22. package/dist/dashboard.d.mts +778 -0
  23. package/dist/dashboard.mjs +1617 -0
  24. package/dist/filter-utils-DqMmy_v-.mjs +72 -0
  25. package/dist/filter-utils-IZ0GtuPo.d.mts +40 -0
  26. package/dist/forms.d.mts +1549 -0
  27. package/dist/forms.mjs +3740 -0
  28. package/dist/index.d.mts +296 -0
  29. package/dist/index.mjs +432 -0
  30. package/dist/layouts.d.mts +215 -0
  31. package/dist/layouts.mjs +460 -0
  32. package/dist/search-context-DR7DBs7S.mjs +19 -0
  33. package/dist/search.d.mts +254 -0
  34. package/dist/search.mjs +523 -0
  35. package/dist/sheet-wrapper-C13Y-Q6w.mjs +211 -0
  36. package/dist/use-base-search-BGgWnWaF.d.mts +35 -0
  37. package/dist/use-debounce-xmZucz5e.mjs +53 -0
  38. package/dist/use-keyboard-shortcut-Bl6YM5Q7.mjs +82 -0
  39. package/dist/use-keyboard-shortcut-_mRCh3QO.d.mts +24 -0
  40. package/dist/use-media-query-BnVNIKT4.mjs +17 -0
  41. package/dist/use-mobile-BX3SQVo2.mjs +20 -0
  42. package/dist/use-scroll-detection-CsgsQYvy.mjs +43 -0
  43. package/dist/utils-CDue7cEt.d.mts +6 -0
  44. package/dist/utils-DQ5SCVoW.mjs +10 -0
  45. package/package.json +85 -45
  46. package/styles.css +2 -2
  47. package/dist/chunk-GUHK2DTW.js +0 -15
  48. package/dist/chunk-GUHK2DTW.js.map +0 -1
  49. package/dist/chunk-H3NFL3GJ.js +0 -57
  50. package/dist/chunk-H3NFL3GJ.js.map +0 -1
  51. package/dist/chunk-J2YRTQE4.js +0 -293
  52. package/dist/chunk-J2YRTQE4.js.map +0 -1
  53. package/dist/compact.d.ts +0 -217
  54. package/dist/compact.js +0 -986
  55. package/dist/compact.js.map +0 -1
  56. package/dist/dashboard.d.ts +0 -387
  57. package/dist/dashboard.js +0 -1032
  58. package/dist/dashboard.js.map +0 -1
  59. package/dist/index.d.ts +0 -2140
  60. package/dist/index.js +0 -6422
  61. package/dist/index.js.map +0 -1
  62. package/dist/layout.d.ts +0 -25
  63. package/dist/layout.js +0 -4
  64. package/dist/layout.js.map +0 -1
  65. package/dist/search.d.ts +0 -172
  66. package/dist/search.js +0 -341
  67. package/dist/search.js.map +0 -1
  68. package/dist/use-base-search-AS5Z3SAy.d.ts +0 -64
  69. package/dist/utils-Cbsgs0XP.d.ts +0 -5
@@ -0,0 +1,2779 @@
1
+ "use client";
2
+
3
+ import { t as cn } from "../utils-DQ5SCVoW.mjs";
4
+ import { t as useMediaQuery } from "../use-media-query-BnVNIKT4.mjs";
5
+ import { n as CustomPagination, r as PaginationInfo, t as ApiPagination } from "../api-pagination-DBTE0yk4.mjs";
6
+ import { i as ClientSubmitButton, n as FormSheet, r as SheetWrapper, t as ConfirmSheet } from "../sheet-wrapper-C13Y-Q6w.mjs";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
9
+ import * as React$1 from "react";
10
+ import { Children, Fragment as Fragment$1, createElement, isValidElement, memo, useEffect, useMemo, useRef, useState } from "react";
11
+ import { AlertCircle, AlertTriangle, ArrowLeft, ArrowRight, Check, CheckCircle2, ChevronDown, ChevronDownIcon, ChevronUp, ChevronUpIcon, Circle, Copy, Info, Loader2, MinusIcon, MoreHorizontal, RefreshCw, X } from "lucide-react";
12
+ import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
13
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
14
+ import { Button } from "@/components/ui/button";
15
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
16
+ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
17
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
18
+ import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
19
+ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
20
+ import { cva } from "class-variance-authority";
21
+ import { Item, ItemContent, ItemDescription } from "@/components/ui/item";
22
+ import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
23
+ import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/ui/input-group";
24
+ import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
25
+ import { ScrollArea } from "@/components/ui/scroll-area";
26
+ import { Badge } from "@/components/ui/badge";
27
+ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
28
+ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
29
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
30
+ import Image from "next/image";
31
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
32
+
33
+ //#region src/components/accordion-wrapper.tsx
34
+ /**
35
+ * AccordionSection - Single collapsible section with smooth animation
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * <AccordionSection title="Settings" icon={<Settings className="h-4 w-4" />}>
40
+ * <div>Content here</div>
41
+ * </AccordionSection>
42
+ * ```
43
+ */
44
+ const AccordionSection = memo(function AccordionSection({ title, icon, children, defaultOpen = false, className, badge }) {
45
+ return /* @__PURE__ */ jsx(Accordion, {
46
+ defaultValue: defaultOpen ? ["section"] : [],
47
+ className,
48
+ children: /* @__PURE__ */ jsxs(AccordionItem, {
49
+ value: "section",
50
+ className: "border-0",
51
+ children: [/* @__PURE__ */ jsx(AccordionTrigger, {
52
+ className: "py-3 hover:no-underline",
53
+ children: /* @__PURE__ */ jsxs("div", {
54
+ className: "flex items-center gap-2",
55
+ children: [
56
+ icon && /* @__PURE__ */ jsx("span", {
57
+ className: "text-muted-foreground",
58
+ children: icon
59
+ }),
60
+ /* @__PURE__ */ jsx("span", {
61
+ className: "font-medium",
62
+ children: title
63
+ }),
64
+ badge
65
+ ]
66
+ })
67
+ }), /* @__PURE__ */ jsx(AccordionContent, { children: /* @__PURE__ */ jsx("div", {
68
+ className: "pt-2",
69
+ children
70
+ }) })]
71
+ })
72
+ });
73
+ });
74
+ /**
75
+ * FaqAccordion - FAQ-style accordion where only one item can be open by default
76
+ *
77
+ * @example
78
+ * ```tsx
79
+ * <FaqAccordion
80
+ * items={[
81
+ * { id: "1", question: "What is this?", answer: "A FAQ accordion" },
82
+ * { id: "2", question: "How does it work?", answer: "Click to expand" },
83
+ * ]}
84
+ * />
85
+ * ```
86
+ */
87
+ const FaqAccordion = memo(function FaqAccordion({ items, defaultOpen, className, multiple = false }) {
88
+ return /* @__PURE__ */ jsx(Accordion, {
89
+ defaultValue: defaultOpen ? [defaultOpen] : [],
90
+ multiple,
91
+ className: cn("w-full", className),
92
+ children: items.map((item) => /* @__PURE__ */ jsxs(AccordionItem, {
93
+ value: item.id,
94
+ children: [/* @__PURE__ */ jsx(AccordionTrigger, {
95
+ className: "text-left",
96
+ children: item.question
97
+ }), /* @__PURE__ */ jsx(AccordionContent, { children: item.answer })]
98
+ }, item.id))
99
+ });
100
+ });
101
+
102
+ //#endregion
103
+ //#region src/components/card-wrapper.tsx
104
+ const CARD_VARIANTS = {
105
+ default: "",
106
+ outline: "border-2",
107
+ ghost: "border-0 shadow-none bg-transparent",
108
+ elevated: "shadow-lg border-0",
109
+ primary: "border-primary/20 bg-primary/5",
110
+ secondary: "border-secondary/20 bg-secondary/5",
111
+ destructive: "border-destructive/20 bg-destructive/5",
112
+ success: "border-green-500/20 bg-green-500/5",
113
+ warning: "border-yellow-500/20 bg-yellow-500/5"
114
+ };
115
+ const CARD_SIZES = {
116
+ sm: "p-3",
117
+ default: "p-6",
118
+ lg: "p-8",
119
+ xl: "p-10"
120
+ };
121
+ const CARD_CONTENT_SIZES = {
122
+ sm: "pt-3",
123
+ default: "pt-6",
124
+ lg: "pt-8",
125
+ xl: "pt-10"
126
+ };
127
+ function CardWrapper({ title, description, children, footer, className, headerClassName, contentClassName, footerClassName, variant = "default", size = "default", hideHeader = false, ...props }) {
128
+ return /* @__PURE__ */ jsxs(Card, {
129
+ className: cn(CARD_VARIANTS[variant], className),
130
+ ...props,
131
+ children: [
132
+ !hideHeader && (title || description) && /* @__PURE__ */ jsxs(CardHeader, {
133
+ className: cn(CARD_SIZES[size], "pb-4", headerClassName),
134
+ children: [title && /* @__PURE__ */ jsx(CardTitle, {
135
+ className: "text-lg font-semibold",
136
+ children: title
137
+ }), description && /* @__PURE__ */ jsx(CardDescription, { children: description })]
138
+ }),
139
+ /* @__PURE__ */ jsx(CardContent, {
140
+ className: cn(hideHeader ? CARD_SIZES[size] : CARD_CONTENT_SIZES[size], contentClassName),
141
+ children
142
+ }),
143
+ footer && /* @__PURE__ */ jsx(CardFooter, {
144
+ className: cn(CARD_SIZES[size], "pt-4 border-t", footerClassName),
145
+ children: /* @__PURE__ */ jsx("div", {
146
+ className: "w-full",
147
+ children: footer
148
+ })
149
+ })
150
+ ]
151
+ });
152
+ }
153
+ const DATA_CARD_COLS = {
154
+ 1: "grid-cols-1",
155
+ 2: "grid-cols-2",
156
+ 3: "grid-cols-2 md:grid-cols-3",
157
+ 4: "grid-cols-2 md:grid-cols-4"
158
+ };
159
+ function DataCard({ title, data, cols = 3, className, ...props }) {
160
+ return /* @__PURE__ */ jsx(CardWrapper, {
161
+ title,
162
+ className: cn("space-y-4", className),
163
+ ...props,
164
+ children: /* @__PURE__ */ jsx("div", {
165
+ className: cn("grid gap-4", DATA_CARD_COLS[cols]),
166
+ children: data.map((item, index) => /* @__PURE__ */ jsxs("div", {
167
+ className: "space-y-1",
168
+ children: [/* @__PURE__ */ jsx("p", {
169
+ className: "text-sm text-muted-foreground",
170
+ children: item.label
171
+ }), /* @__PURE__ */ jsx("p", {
172
+ className: cn("text-lg font-semibold", item.color),
173
+ children: item.value
174
+ })]
175
+ }, index))
176
+ })
177
+ });
178
+ }
179
+ function LoadingCard({ title, description, className, ...props }) {
180
+ return /* @__PURE__ */ jsx(CardWrapper, {
181
+ title,
182
+ description,
183
+ className,
184
+ ...props,
185
+ children: /* @__PURE__ */ jsxs("div", {
186
+ className: "flex items-center justify-center py-8",
187
+ children: [/* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary" }), /* @__PURE__ */ jsx("span", {
188
+ className: "ml-2",
189
+ children: "Loading..."
190
+ })]
191
+ })
192
+ });
193
+ }
194
+ const STATS_CARD_VARIANTS = {
195
+ default: "",
196
+ success: "bg-green-50 border-green-200 dark:bg-green-950/30 dark:border-green-900",
197
+ warning: "bg-yellow-50 border-yellow-200 dark:bg-yellow-950/30 dark:border-yellow-900",
198
+ danger: "bg-red-50 border-red-200 dark:bg-red-950/30 dark:border-red-900",
199
+ info: "bg-blue-50 border-blue-200 dark:bg-blue-950/30 dark:border-blue-900"
200
+ };
201
+ const STATS_ICON_VARIANTS = {
202
+ default: "text-muted-foreground",
203
+ success: "text-green-600 dark:text-green-400",
204
+ warning: "text-yellow-600 dark:text-yellow-400",
205
+ danger: "text-red-600 dark:text-red-400",
206
+ info: "text-blue-600 dark:text-blue-400"
207
+ };
208
+ const STATS_ICON_WRAPPER_VARIANTS = {
209
+ default: "bg-muted border border-border",
210
+ success: "bg-green-100/50 dark:bg-green-900/30",
211
+ warning: "bg-yellow-100/50 dark:bg-yellow-900/30",
212
+ danger: "bg-red-100/50 dark:bg-red-900/30",
213
+ info: "bg-blue-100/50 dark:bg-blue-900/30"
214
+ };
215
+ function StatsCard({ title, value, description, icon, trend, className, statsVariant = "default", iconClassName, ...props }) {
216
+ return /* @__PURE__ */ jsxs(CardWrapper, {
217
+ className: cn("relative overflow-hidden", STATS_CARD_VARIANTS[statsVariant], className),
218
+ size: "sm",
219
+ hideHeader: true,
220
+ ...props,
221
+ children: [/* @__PURE__ */ jsxs("div", {
222
+ className: "flex items-center justify-between",
223
+ children: [/* @__PURE__ */ jsxs("div", {
224
+ className: "space-y-1",
225
+ children: [
226
+ /* @__PURE__ */ jsx("p", {
227
+ className: "text-sm font-medium text-muted-foreground",
228
+ children: title
229
+ }),
230
+ /* @__PURE__ */ jsx("p", {
231
+ className: "text-2xl font-bold",
232
+ children: value
233
+ }),
234
+ description && /* @__PURE__ */ jsx("p", {
235
+ className: "text-xs text-muted-foreground",
236
+ children: description
237
+ })
238
+ ]
239
+ }), icon && /* @__PURE__ */ jsx("div", {
240
+ className: cn("p-2 rounded-md", STATS_ICON_WRAPPER_VARIANTS[statsVariant], STATS_ICON_VARIANTS[statsVariant], iconClassName),
241
+ children: icon
242
+ })]
243
+ }), trend && /* @__PURE__ */ jsx("div", {
244
+ className: cn("absolute top-2 right-2 text-xs px-2 py-1 rounded-full", trend.type === "up" && "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300", trend.type === "down" && "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300", trend.type === "neutral" && "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300"),
245
+ children: trend.value
246
+ })]
247
+ });
248
+ }
249
+ function DraggableCard({ title, subtitle, badges, actions, details, dragHandleProps, className, isDragging, isHidden, children, ...props }) {
250
+ return /* @__PURE__ */ jsx(CardWrapper, {
251
+ hideHeader: true,
252
+ className: cn("transition-all", isDragging && "shadow-lg rotate-2", isHidden && "opacity-50", className),
253
+ contentClassName: "!pt-4",
254
+ ...props,
255
+ children: /* @__PURE__ */ jsxs("div", {
256
+ className: "flex items-start gap-3",
257
+ children: [
258
+ dragHandleProps && /* @__PURE__ */ jsx("div", {
259
+ ...dragHandleProps,
260
+ className: "mt-1 cursor-grab hover:text-foreground",
261
+ children: dragHandleProps.icon || /* @__PURE__ */ jsxs("svg", {
262
+ xmlns: "http://www.w3.org/2000/svg",
263
+ width: "16",
264
+ height: "16",
265
+ viewBox: "0 0 24 24",
266
+ fill: "none",
267
+ stroke: "currentColor",
268
+ strokeWidth: "2",
269
+ strokeLinecap: "round",
270
+ strokeLinejoin: "round",
271
+ className: "text-muted-foreground",
272
+ children: [
273
+ /* @__PURE__ */ jsx("circle", {
274
+ cx: "9",
275
+ cy: "12",
276
+ r: "1"
277
+ }),
278
+ /* @__PURE__ */ jsx("circle", {
279
+ cx: "9",
280
+ cy: "5",
281
+ r: "1"
282
+ }),
283
+ /* @__PURE__ */ jsx("circle", {
284
+ cx: "9",
285
+ cy: "19",
286
+ r: "1"
287
+ }),
288
+ /* @__PURE__ */ jsx("circle", {
289
+ cx: "15",
290
+ cy: "12",
291
+ r: "1"
292
+ }),
293
+ /* @__PURE__ */ jsx("circle", {
294
+ cx: "15",
295
+ cy: "5",
296
+ r: "1"
297
+ }),
298
+ /* @__PURE__ */ jsx("circle", {
299
+ cx: "15",
300
+ cy: "19",
301
+ r: "1"
302
+ })
303
+ ]
304
+ })
305
+ }),
306
+ /* @__PURE__ */ jsxs("div", {
307
+ className: "flex-1 min-w-0 space-y-3",
308
+ children: [
309
+ /* @__PURE__ */ jsxs("div", {
310
+ className: "flex flex-wrap items-center gap-2",
311
+ children: [title && /* @__PURE__ */ jsx("h4", {
312
+ className: "font-medium",
313
+ children: title
314
+ }), badges && /* @__PURE__ */ jsx("div", {
315
+ className: "flex flex-wrap gap-1",
316
+ children: badges
317
+ })]
318
+ }),
319
+ subtitle && /* @__PURE__ */ jsx("p", {
320
+ className: "text-xs text-muted-foreground break-words",
321
+ children: subtitle
322
+ }),
323
+ details,
324
+ children
325
+ ]
326
+ }),
327
+ actions && /* @__PURE__ */ jsx("div", {
328
+ className: "flex items-center gap-2 flex-shrink-0",
329
+ children: actions
330
+ })
331
+ ]
332
+ })
333
+ });
334
+ }
335
+
336
+ //#endregion
337
+ //#region src/components/collapsible-wrapper.tsx
338
+ function CollapsibleWrapper({ children, trigger, defaultOpen = false, open, onOpenChange, triggerAsChild = false, triggerVariant = "outline", triggerSize = "sm", triggerClassName, contentClassName, className, showChevron = true, chevronPosition = "right", disabled = false, ...props }) {
339
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
340
+ const isOpen = open !== void 0 ? open : internalOpen;
341
+ const handleOpenChange = onOpenChange || setInternalOpen;
342
+ const chevronElement = showChevron && /* @__PURE__ */ jsx("div", {
343
+ className: cn("flex items-center", chevronPosition === "left" && "order-first mr-2", chevronPosition === "right" && "ml-2"),
344
+ children: isOpen ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
345
+ });
346
+ return /* @__PURE__ */ jsxs(Collapsible, {
347
+ open: isOpen,
348
+ onOpenChange: handleOpenChange,
349
+ disabled,
350
+ className: cn("w-full", className),
351
+ ...props,
352
+ children: [triggerAsChild && isValidElement(trigger) ? /* @__PURE__ */ jsx(CollapsibleTrigger, { render: trigger }) : /* @__PURE__ */ jsxs(CollapsibleTrigger, {
353
+ render: /* @__PURE__ */ jsx(Button, {
354
+ variant: triggerVariant,
355
+ size: triggerSize,
356
+ disabled,
357
+ className: cn("justify-between", triggerClassName)
358
+ }),
359
+ children: [trigger, chevronElement]
360
+ }), /* @__PURE__ */ jsx(CollapsibleContent, {
361
+ className: cn("mt-2", contentClassName),
362
+ children
363
+ })]
364
+ });
365
+ }
366
+ function CollapsibleCard({ title, children, defaultOpen = false, className, headerClassName, contentClassName, ...props }) {
367
+ const [isOpen, setIsOpen] = useState(defaultOpen);
368
+ return /* @__PURE__ */ jsxs(Collapsible, {
369
+ open: isOpen,
370
+ onOpenChange: setIsOpen,
371
+ className: cn("border rounded-lg overflow-hidden", className),
372
+ ...props,
373
+ children: [/* @__PURE__ */ jsxs(CollapsibleTrigger, {
374
+ render: /* @__PURE__ */ jsx("button", {
375
+ type: "button",
376
+ className: cn("flex items-center justify-between w-full px-4 py-3 cursor-pointer transition-colors hover:bg-secondary/5 bg-transparent border-0 text-left", headerClassName)
377
+ }),
378
+ children: [/* @__PURE__ */ jsx("span", {
379
+ className: "font-medium",
380
+ children: title
381
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200", isOpen && "rotate-180") })]
382
+ }), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", {
383
+ className: cn("px-4 py-3 border-t", contentClassName),
384
+ children
385
+ }) })]
386
+ });
387
+ }
388
+ function CollapsibleSection({ label, children, defaultOpen = false, className, labelClassName, contentClassName, ...props }) {
389
+ return /* @__PURE__ */ jsx(CollapsibleWrapper, {
390
+ trigger: label,
391
+ defaultOpen,
392
+ triggerVariant: "ghost",
393
+ triggerSize: "sm",
394
+ triggerClassName: cn("h-8 px-2 font-medium justify-between", labelClassName),
395
+ contentClassName: cn("pl-4 mt-1", contentClassName),
396
+ className: cn("space-y-1", className),
397
+ ...props,
398
+ children
399
+ });
400
+ }
401
+
402
+ //#endregion
403
+ //#region src/components/confirm-dialog.tsx
404
+ function ConfirmDialog({ open, onOpenChange, trigger, title = "Are you sure?", description = "This action cannot be undone.", confirmText = "Confirm", cancelText = "Cancel", variant = "destructive", isLoading = false, onConfirm, onCancel, icon, children, className, headerClassName, descriptionClassName, footerClassName, showCancel = true, ...props }) {
405
+ const handleConfirm = () => {
406
+ if (onConfirm) onConfirm();
407
+ };
408
+ const handleCancel = () => {
409
+ if (onCancel) onCancel();
410
+ else onOpenChange(false);
411
+ };
412
+ const triggerChildren = (trigger?.props)?.children;
413
+ const triggerElement = trigger ? React$1.cloneElement(trigger, { children: void 0 }) : null;
414
+ return /* @__PURE__ */ jsxs(AlertDialog, {
415
+ open,
416
+ onOpenChange,
417
+ ...props,
418
+ children: [triggerElement && /* @__PURE__ */ jsx(AlertDialogTrigger, {
419
+ render: triggerElement,
420
+ children: triggerChildren
421
+ }), /* @__PURE__ */ jsxs(AlertDialogContent, {
422
+ className: cn("max-w-md", className),
423
+ children: [
424
+ /* @__PURE__ */ jsxs(AlertDialogHeader, {
425
+ className: cn(headerClassName),
426
+ children: [/* @__PURE__ */ jsxs(AlertDialogTitle, {
427
+ className: "flex items-center gap-2",
428
+ children: [icon || variant === "destructive" && /* @__PURE__ */ jsx(AlertTriangle, { className: "h-5 w-5 text-destructive" }), title]
429
+ }), description && /* @__PURE__ */ jsx(AlertDialogDescription, {
430
+ className: cn(descriptionClassName),
431
+ children: description
432
+ })]
433
+ }),
434
+ children && /* @__PURE__ */ jsx("div", {
435
+ className: "py-4",
436
+ children
437
+ }),
438
+ /* @__PURE__ */ jsxs(AlertDialogFooter, {
439
+ className: cn(footerClassName),
440
+ children: [showCancel && /* @__PURE__ */ jsx(AlertDialogCancel, {
441
+ onClick: handleCancel,
442
+ disabled: isLoading,
443
+ children: cancelText
444
+ }), onConfirm && /* @__PURE__ */ jsx(AlertDialogAction, {
445
+ onClick: handleConfirm,
446
+ disabled: isLoading,
447
+ variant,
448
+ children: isLoading ? /* @__PURE__ */ jsxs("div", {
449
+ className: "flex items-center gap-2",
450
+ children: [/* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }), "Loading..."]
451
+ }) : confirmText
452
+ })]
453
+ })
454
+ ]
455
+ })]
456
+ });
457
+ }
458
+ function DeleteConfirmDialog({ open, onOpenChange, onConfirm, isLoading = false, itemName = "item", itemDetails, ...props }) {
459
+ return /* @__PURE__ */ jsx(ConfirmDialog, {
460
+ open,
461
+ onOpenChange,
462
+ title: "Delete Item",
463
+ description: `Are you sure you want to delete this ${itemName}? This action cannot be undone.`,
464
+ confirmText: "Yes, Delete",
465
+ cancelText: "No",
466
+ variant: "destructive",
467
+ isLoading,
468
+ onConfirm,
469
+ ...props,
470
+ children: itemDetails && /* @__PURE__ */ jsx("div", {
471
+ className: "bg-muted/50 p-3 rounded-md",
472
+ children: /* @__PURE__ */ jsx("div", {
473
+ className: "text-sm space-y-1",
474
+ children: itemDetails
475
+ })
476
+ })
477
+ });
478
+ }
479
+ /**
480
+ * InfoAlert - Information/warning alert with only confirm button (no cancel)
481
+ *
482
+ * @example
483
+ * ```tsx
484
+ * <InfoAlert
485
+ * open={open}
486
+ * onOpenChange={setOpen}
487
+ * title="Session expired"
488
+ * description="Please log in again"
489
+ * confirmText="OK"
490
+ * onConfirm={() => setOpen(false)}
491
+ * />
492
+ * ```
493
+ */
494
+ function InfoAlert({ title, description, confirmText = "OK", onConfirm, onOpenChange, ...props }) {
495
+ return /* @__PURE__ */ jsx(ConfirmDialog, {
496
+ title,
497
+ description,
498
+ confirmText,
499
+ variant: "default",
500
+ showCancel: false,
501
+ onConfirm: onConfirm || (() => onOpenChange(false)),
502
+ onOpenChange,
503
+ ...props
504
+ });
505
+ }
506
+
507
+ //#endregion
508
+ //#region src/components/copy-button.tsx
509
+ async function copyToClipboard(text, options) {
510
+ try {
511
+ await navigator.clipboard.writeText(text);
512
+ return true;
513
+ } catch {
514
+ return false;
515
+ }
516
+ }
517
+ function CopyButton({ value, className, size = "sm", variant = "ghost", showToast = true, toastMessage = "Copied to clipboard", errorMessage = "Failed to copy to clipboard", timeout = 2e3, children, ...props }) {
518
+ const [copied, setCopied] = useState(false);
519
+ const handleCopy = async () => {
520
+ if (!value) return;
521
+ if (await copyToClipboard(value, {
522
+ showToast,
523
+ successMessage: toastMessage,
524
+ errorMessage
525
+ })) {
526
+ setCopied(true);
527
+ setTimeout(() => setCopied(false), timeout);
528
+ }
529
+ };
530
+ return /* @__PURE__ */ jsx(Button, {
531
+ variant,
532
+ size,
533
+ className: cn("h-6 w-6 p-0", className),
534
+ onClick: handleCopy,
535
+ disabled: !value,
536
+ ...props,
537
+ children: children || (copied ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 text-green-600" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3" }))
538
+ });
539
+ }
540
+ function CopyText({ value, displayValue, className, textClassName, buttonClassName, maxLength = 30, showButton = true, ...buttonProps }) {
541
+ const truncatedValue = displayValue || (value && value.length > maxLength ? `${value.substring(0, maxLength)}...` : value || "N/A");
542
+ return /* @__PURE__ */ jsxs("div", {
543
+ className: cn("flex items-center gap-2", className),
544
+ children: [/* @__PURE__ */ jsx("span", {
545
+ className: cn("font-medium", textClassName),
546
+ title: value || "N/A",
547
+ children: truncatedValue
548
+ }), showButton && value && /* @__PURE__ */ jsx(CopyButton, {
549
+ value,
550
+ className: buttonClassName,
551
+ ...buttonProps
552
+ })]
553
+ });
554
+ }
555
+ function CopyCodeBlock({ value, className, language, showLineNumbers = false, ...buttonProps }) {
556
+ return /* @__PURE__ */ jsxs("div", {
557
+ className: cn("relative group", className),
558
+ children: [/* @__PURE__ */ jsx("pre", {
559
+ className: "bg-muted p-4 rounded-md overflow-x-auto text-sm",
560
+ children: /* @__PURE__ */ jsx("code", {
561
+ className: language ? `language-${language}` : "",
562
+ children: value
563
+ })
564
+ }), /* @__PURE__ */ jsx("div", {
565
+ className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity",
566
+ children: /* @__PURE__ */ jsx(CopyButton, {
567
+ value,
568
+ variant: "secondary",
569
+ size: "sm",
570
+ ...buttonProps
571
+ })
572
+ })]
573
+ });
574
+ }
575
+
576
+ //#endregion
577
+ //#region src/components/dialog-wrapper.tsx
578
+ const SIZE_VARIANTS = {
579
+ sm: "sm:max-w-sm",
580
+ default: "sm:max-w-md",
581
+ lg: "sm:max-w-lg md:max-w-2xl",
582
+ xl: "sm:max-w-2xl md:max-w-4xl",
583
+ "2xl": "sm:max-w-4xl md:max-w-6xl",
584
+ full: "max-w-[95vw] h-[95vh]"
585
+ };
586
+ function DialogWrapper({ open, onOpenChange, title, description, children, footer, trigger, size = "default", className, headerClassName, contentClassName, footerClassName, hideHeader = false, hideTitle = false, hideDescription = false, hideCloseButton = false, ...props }) {
587
+ return /* @__PURE__ */ jsxs(Dialog, {
588
+ open,
589
+ onOpenChange,
590
+ ...props,
591
+ children: [trigger && /* @__PURE__ */ jsx(DialogTrigger, { render: trigger }), /* @__PURE__ */ jsxs(DialogContent, {
592
+ showCloseButton: !hideCloseButton,
593
+ className: cn("max-w-none", SIZE_VARIANTS[size], contentClassName, className),
594
+ children: [
595
+ !hideHeader && /* @__PURE__ */ jsxs(DialogHeader, {
596
+ className: cn("space-y-2", headerClassName),
597
+ children: [hideTitle ? /* @__PURE__ */ jsx(DialogTitle, {
598
+ className: "sr-only",
599
+ children: title || "Dialog"
600
+ }) : /* @__PURE__ */ jsx(DialogTitle, { children: title || "Dialog" }), description && (hideDescription ? /* @__PURE__ */ jsx(DialogDescription, {
601
+ className: "sr-only",
602
+ children: description
603
+ }) : /* @__PURE__ */ jsx(DialogDescription, { children: description }))]
604
+ }),
605
+ children,
606
+ footer && /* @__PURE__ */ jsx(DialogFooter, {
607
+ className: cn("gap-2", footerClassName),
608
+ children: footer
609
+ })
610
+ ]
611
+ })]
612
+ });
613
+ }
614
+ function FormDialog({ open, onOpenChange, title, description, children, onSubmit, onCancel, submitText = "Save", cancelText = "Cancel", isLoading = false, submitDisabled = false, ...props }) {
615
+ const handleSubmit = (e) => {
616
+ e.preventDefault();
617
+ onSubmit?.(e);
618
+ };
619
+ return /* @__PURE__ */ jsx(DialogWrapper, {
620
+ open,
621
+ onOpenChange,
622
+ title,
623
+ description,
624
+ ...props,
625
+ children: /* @__PURE__ */ jsxs("form", {
626
+ onSubmit: handleSubmit,
627
+ children: [children, /* @__PURE__ */ jsxs(DialogFooter, {
628
+ className: "gap-2 mt-4",
629
+ children: [/* @__PURE__ */ jsx(Button, {
630
+ type: "button",
631
+ variant: "outline",
632
+ onClick: onCancel || (() => onOpenChange(false)),
633
+ disabled: isLoading,
634
+ children: cancelText
635
+ }), /* @__PURE__ */ jsx(Button, {
636
+ type: "submit",
637
+ disabled: isLoading || submitDisabled,
638
+ children: isLoading ? "Loading..." : submitText
639
+ })]
640
+ })]
641
+ })
642
+ });
643
+ }
644
+
645
+ //#endregion
646
+ //#region src/components/dropdown-wrapper.tsx
647
+ function DropdownWrapper({ trigger, children, align = "end", side = "bottom", sideOffset = 4, className, contentClassName, ...props }) {
648
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
649
+ ...props,
650
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
651
+ align,
652
+ side,
653
+ sideOffset,
654
+ className: cn("min-w-[160px]", contentClassName),
655
+ children
656
+ })]
657
+ });
658
+ }
659
+ function ActionDropdown({ items = [], triggerIcon: TriggerIcon = MoreHorizontal, triggerVariant = "ghost", triggerSize = "sm", triggerClassName, triggerLabel, showOnHover = false, align = "end", contentClassName, onOpenChange, stopPropagation = true, ...props }) {
660
+ const handleTriggerClick = (e) => {
661
+ if (stopPropagation) e.stopPropagation();
662
+ };
663
+ const trigger = /* @__PURE__ */ jsxs(Button, {
664
+ variant: triggerVariant,
665
+ size: triggerSize,
666
+ onClick: handleTriggerClick,
667
+ className: cn(showOnHover && "opacity-0 group-hover:opacity-100 transition-opacity", triggerClassName),
668
+ children: [
669
+ /* @__PURE__ */ jsx(TriggerIcon, { className: "h-4 w-4" }),
670
+ triggerLabel && /* @__PURE__ */ jsx("span", {
671
+ className: "ml-2",
672
+ children: triggerLabel
673
+ }),
674
+ /* @__PURE__ */ jsx("span", {
675
+ className: "sr-only",
676
+ children: "Open menu"
677
+ })
678
+ ]
679
+ });
680
+ const handleItemClick = (item) => (e) => {
681
+ if (stopPropagation) e.stopPropagation();
682
+ item.onClick?.(e);
683
+ };
684
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
685
+ onOpenChange,
686
+ ...props,
687
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
688
+ align,
689
+ className: cn("min-w-[180px]", contentClassName),
690
+ children: items.map((item, index) => {
691
+ if (item.hidden) return null;
692
+ if (item.type === "separator") return /* @__PURE__ */ jsx(DropdownMenuSeparator, {}, item.key || `separator-${index}`);
693
+ if (item.type === "label") return /* @__PURE__ */ jsx(DropdownMenuGroup, { children: /* @__PURE__ */ jsx(DropdownMenuLabel, {
694
+ className: item.className,
695
+ children: item.label
696
+ }) }, item.key || `label-${index}`);
697
+ if (item.type === "group") return /* @__PURE__ */ jsx(DropdownMenuGroup, { children: item.items?.map((groupItem, groupIndex) => {
698
+ if (groupItem.hidden) return null;
699
+ const GroupItemIcon = groupItem.icon;
700
+ const groupItemLabel = typeof groupItem.label === "function" ? groupItem.label() : groupItem.label;
701
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, {
702
+ onClick: handleItemClick(groupItem),
703
+ disabled: groupItem.disabled,
704
+ className: cn(groupItem.variant === "destructive" && "text-destructive focus:text-destructive", groupItem.className),
705
+ children: [
706
+ GroupItemIcon && /* @__PURE__ */ jsx(GroupItemIcon, { className: "h-4 w-4" }),
707
+ /* @__PURE__ */ jsx("span", { children: groupItemLabel }),
708
+ groupItem.shortcut && /* @__PURE__ */ jsx("span", {
709
+ className: "ml-auto text-xs tracking-widest text-muted-foreground",
710
+ children: groupItem.shortcut
711
+ })
712
+ ]
713
+ }, groupItem.key || `group-item-${groupIndex}`);
714
+ }) }, item.key || `group-${index}`);
715
+ const ItemIcon = item.icon;
716
+ const displayLabel = typeof item.label === "function" ? item.label() : item.label;
717
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, {
718
+ onClick: handleItemClick(item),
719
+ disabled: item.disabled,
720
+ className: cn(item.variant === "destructive" && "text-destructive focus:text-destructive", item.className),
721
+ children: [
722
+ ItemIcon && /* @__PURE__ */ jsx(ItemIcon, { className: "h-4 w-4" }),
723
+ /* @__PURE__ */ jsx("span", { children: displayLabel }),
724
+ item.shortcut && /* @__PURE__ */ jsx("span", {
725
+ className: "ml-auto text-xs tracking-widest text-muted-foreground",
726
+ children: item.shortcut
727
+ })
728
+ ]
729
+ }, item.key || `item-${index}`);
730
+ })
731
+ })]
732
+ });
733
+ }
734
+ function SelectDropdown({ value, onValueChange, placeholder = "Select option...", options = [], triggerClassName, contentClassName, disabled = false, ...props }) {
735
+ const selectedOption = options.find((option) => option.value === value);
736
+ const trigger = /* @__PURE__ */ jsxs(Button, {
737
+ variant: "outline",
738
+ disabled,
739
+ className: cn("w-full justify-between", !selectedOption && "text-muted-foreground", triggerClassName),
740
+ children: [selectedOption ? selectedOption.label : placeholder, /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
741
+ });
742
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
743
+ ...props,
744
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
745
+ align: "start",
746
+ className: cn("w-full min-w-(--anchor-width)", contentClassName),
747
+ children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
748
+ onClick: () => onValueChange?.(option.value),
749
+ className: cn("cursor-pointer", value === option.value && "bg-accent"),
750
+ children: [option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }), option.label]
751
+ }, option.value))
752
+ })]
753
+ });
754
+ }
755
+ function CheckboxDropdown({ values = [], onValuesChange, placeholder = "Select options...", options = [], triggerClassName, contentClassName, disabled = false, showSelectedCount = true, ...props }) {
756
+ const selectedOptions = options.filter((option) => values.includes(option.value));
757
+ const displayText = selectedOptions.length > 0 ? showSelectedCount ? `${selectedOptions.length} selected` : selectedOptions.map((opt) => opt.label).join(", ") : placeholder;
758
+ const trigger = /* @__PURE__ */ jsxs(Button, {
759
+ variant: "outline",
760
+ disabled,
761
+ className: cn("w-full justify-between", selectedOptions.length === 0 && "text-muted-foreground", triggerClassName),
762
+ children: [/* @__PURE__ */ jsx("span", {
763
+ className: "truncate",
764
+ children: displayText
765
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
766
+ });
767
+ const handleCheckedChange = (optionValue, checked) => {
768
+ if (checked) onValuesChange?.([...values, optionValue]);
769
+ else onValuesChange?.(values.filter((value) => value !== optionValue));
770
+ };
771
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
772
+ ...props,
773
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
774
+ align: "start",
775
+ className: cn("w-full min-w-(--anchor-width)", contentClassName),
776
+ children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuCheckboxItem, {
777
+ checked: values.includes(option.value),
778
+ onCheckedChange: (checked) => handleCheckedChange(option.value, checked),
779
+ children: [option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }), option.label]
780
+ }, option.value))
781
+ })]
782
+ });
783
+ }
784
+ function RadioDropdown({ value, onValueChange, placeholder = "Select option...", options = [], triggerClassName, contentClassName, disabled = false, ...props }) {
785
+ const selectedOption = options.find((option) => option.value === value);
786
+ const trigger = /* @__PURE__ */ jsxs(Button, {
787
+ variant: "outline",
788
+ disabled,
789
+ className: cn("w-full justify-between", !selectedOption && "text-muted-foreground", triggerClassName),
790
+ children: [selectedOption ? selectedOption.label : placeholder, /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
791
+ });
792
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
793
+ ...props,
794
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
795
+ align: "start",
796
+ className: cn("w-full min-w-(--anchor-width)", contentClassName),
797
+ children: /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
798
+ value,
799
+ onValueChange,
800
+ children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuRadioItem, {
801
+ value: option.value,
802
+ children: [option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }), option.label]
803
+ }, option.value))
804
+ })
805
+ })]
806
+ });
807
+ }
808
+
809
+ //#endregion
810
+ //#region src/components/error-state.tsx
811
+ /**
812
+ * ErrorState Component
813
+ *
814
+ * Reusable error display component with retry functionality
815
+ * Used for consistent error handling across pages
816
+ */
817
+ function ErrorState({ title = "Error", error, onRetry, variant = "destructive", className, icon }) {
818
+ const errorMessage = typeof error === "string" ? error : error?.message || "Something went wrong. Please try again.";
819
+ return /* @__PURE__ */ jsxs(Alert, {
820
+ variant,
821
+ className: cn(className),
822
+ children: [
823
+ icon || /* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4" }),
824
+ /* @__PURE__ */ jsx(AlertTitle, { children: title }),
825
+ /* @__PURE__ */ jsxs(AlertDescription, {
826
+ className: "mt-2 flex flex-col gap-3",
827
+ children: [/* @__PURE__ */ jsx("p", {
828
+ className: "text-sm",
829
+ children: errorMessage
830
+ }), onRetry && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Button, {
831
+ onClick: onRetry,
832
+ variant: "outline",
833
+ size: "sm",
834
+ className: "gap-2",
835
+ children: [/* @__PURE__ */ jsx(RefreshCw, { className: "h-3 w-3" }), "Try Again"]
836
+ }) })]
837
+ })
838
+ ]
839
+ });
840
+ }
841
+ /**
842
+ * Inline ErrorState variant - more compact for table cells
843
+ */
844
+ function ErrorStateInline({ error, onRetry, className, icon }) {
845
+ const errorMessage = typeof error === "string" ? error : error?.message || "Error loading data";
846
+ return /* @__PURE__ */ jsxs("div", {
847
+ className: cn("flex items-center gap-2 text-sm text-destructive", className),
848
+ children: [
849
+ icon || /* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4" }),
850
+ /* @__PURE__ */ jsx("span", { children: errorMessage }),
851
+ onRetry && /* @__PURE__ */ jsxs(Button, {
852
+ onClick: onRetry,
853
+ variant: "ghost",
854
+ size: "sm",
855
+ className: "h-6 px-2 gap-1",
856
+ children: [/* @__PURE__ */ jsx(RefreshCw, { className: "h-3 w-3" }), "Retry"]
857
+ })
858
+ ]
859
+ });
860
+ }
861
+
862
+ //#endregion
863
+ //#region src/components/info-row.tsx
864
+ function InfoRow({ label, value, copyable = false, icon: Icon }) {
865
+ if (!value && value !== 0) return null;
866
+ return /* @__PURE__ */ jsxs("div", {
867
+ className: "flex flex-col sm:flex-row sm:justify-between sm:items-center py-3 gap-2 group hover:bg-muted rounded-md px-3 -mx-3 transition-colors",
868
+ children: [/* @__PURE__ */ jsxs("div", {
869
+ className: "flex items-center gap-2 min-w-0",
870
+ children: [Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 text-muted-foreground flex-shrink-0" }), /* @__PURE__ */ jsx("span", {
871
+ className: "text-sm font-medium text-muted-foreground truncate",
872
+ children: label
873
+ })]
874
+ }), /* @__PURE__ */ jsx("div", {
875
+ className: "sm:text-right min-w-0 flex-shrink-0",
876
+ children: copyable ? /* @__PURE__ */ jsx(CopyText, {
877
+ value: String(value),
878
+ textClassName: "text-foreground font-semibold",
879
+ maxLength: 40,
880
+ className: "justify-start sm:justify-end"
881
+ }) : /* @__PURE__ */ jsx("span", {
882
+ className: "font-semibold text-foreground block truncate max-w-full sm:max-w-[250px]",
883
+ title: value?.toString() || "N/A",
884
+ children: value?.toString() || "N/A"
885
+ })
886
+ })]
887
+ });
888
+ }
889
+
890
+ //#endregion
891
+ //#region src/components/item-helpers.tsx
892
+ /**
893
+ * Item Component Helpers
894
+ */
895
+ const iconItemMediaVariants = cva("rounded-xl flex items-center justify-center shrink-0", {
896
+ variants: {
897
+ iconBg: {
898
+ primary: "bg-primary/10 text-primary",
899
+ gold: "bg-primary/20 text-primary",
900
+ muted: "bg-muted text-foreground",
901
+ gradient: "bg-gradient-to-br from-primary/20 to-primary/10 text-primary",
902
+ none: "bg-transparent"
903
+ },
904
+ iconSize: {
905
+ sm: "size-8",
906
+ md: "size-10 md:size-12",
907
+ lg: "size-12 md:size-14",
908
+ xl: "size-16 md:size-20"
909
+ }
910
+ },
911
+ defaultVariants: {
912
+ iconBg: "primary",
913
+ iconSize: "md"
914
+ }
915
+ });
916
+ const IconItemMedia = React$1.memo(function IconItemMedia({ icon, iconBg = "primary", iconSize = "md", className, children, ...props }) {
917
+ return /* @__PURE__ */ jsx("div", {
918
+ "data-slot": "item-media",
919
+ role: "presentation",
920
+ className: cn(iconItemMediaVariants({
921
+ iconBg,
922
+ iconSize
923
+ }), className),
924
+ ...props,
925
+ children: children || icon
926
+ });
927
+ });
928
+ IconItemMedia.displayName = "IconItemMedia";
929
+ const FeatureItem = React$1.memo(function FeatureItem({ icon, iconBg = "primary", iconSize = "md", title, description, variant = "outline", size = "default", layout = "vertical", titleAs = "h3", className, titleClassName, descriptionClassName, iconClassName, children, ...props }) {
930
+ const hasGradientBorder = variant === "gradient-light" || variant === "gradient";
931
+ const TitleComponent = titleAs;
932
+ if (hasGradientBorder) return /* @__PURE__ */ jsx("div", {
933
+ className: cn(variant === "gradient-light" ? "gradient-border-light" : "gradient-border", "rounded-2xl hover:gradient-border-hover transition-all duration-300", className),
934
+ children: /* @__PURE__ */ jsxs("div", {
935
+ className: cn("gradient-border-inner rounded-2xl p-6 flex", layout === "vertical" ? "flex-col items-start gap-4" : "flex-row items-center gap-4"),
936
+ children: [icon && /* @__PURE__ */ jsx(IconItemMedia, {
937
+ icon,
938
+ iconBg,
939
+ iconSize,
940
+ className: cn(layout === "vertical" ? "" : "shrink-0", iconClassName)
941
+ }), /* @__PURE__ */ jsxs("div", {
942
+ className: "flex flex-col gap-2 flex-1",
943
+ children: [
944
+ title && /* @__PURE__ */ jsx(TitleComponent, {
945
+ className: cn("text-base md:text-lg font-semibold text-foreground leading-tight", titleClassName),
946
+ children: title
947
+ }),
948
+ description && /* @__PURE__ */ jsx("p", {
949
+ className: cn("text-sm text-muted-foreground leading-relaxed", descriptionClassName),
950
+ children: description
951
+ }),
952
+ children
953
+ ]
954
+ })]
955
+ })
956
+ });
957
+ return /* @__PURE__ */ jsxs(Item, {
958
+ variant,
959
+ size,
960
+ className: cn(layout === "vertical" && "flex-col items-start", className),
961
+ ...props,
962
+ children: [icon && /* @__PURE__ */ jsx(IconItemMedia, {
963
+ icon,
964
+ iconBg,
965
+ iconSize,
966
+ className: iconClassName
967
+ }), /* @__PURE__ */ jsxs(ItemContent, { children: [
968
+ title && /* @__PURE__ */ jsx(TitleComponent, {
969
+ "data-slot": "item-title",
970
+ className: cn("text-base md:text-lg font-semibold text-foreground leading-tight mb-2", titleClassName),
971
+ children: title
972
+ }),
973
+ description && /* @__PURE__ */ jsx(ItemDescription, {
974
+ className: cn("text-sm text-muted-foreground leading-relaxed", descriptionClassName),
975
+ children: description
976
+ }),
977
+ children
978
+ ] })]
979
+ });
980
+ });
981
+ FeatureItem.displayName = "FeatureItem";
982
+ function FeatureList({ items = [], columns = 3, variant = "outline", iconBg = "primary", iconSize = "md", layout = "vertical", className, itemClassName, ...props }) {
983
+ const gridCols = {
984
+ 2: "md:grid-cols-2",
985
+ 3: "md:grid-cols-2 lg:grid-cols-3",
986
+ 4: "md:grid-cols-2 lg:grid-cols-4"
987
+ };
988
+ return /* @__PURE__ */ jsx("div", {
989
+ role: "list",
990
+ className: cn("grid gap-6", gridCols[columns] || gridCols[3], className),
991
+ ...props,
992
+ children: items.map((item, index) => /* @__PURE__ */ jsx(FeatureItem, {
993
+ icon: item.icon,
994
+ iconBg: item.iconBg || iconBg,
995
+ iconSize: item.iconSize || iconSize,
996
+ title: item.title,
997
+ description: item.description,
998
+ variant,
999
+ layout,
1000
+ className: itemClassName
1001
+ }, item.id || item.title || index))
1002
+ });
1003
+ }
1004
+ FeatureList.displayName = "FeatureList";
1005
+
1006
+ //#endregion
1007
+ //#region src/components/phone-input.tsx
1008
+ const DEFAULT_COUNTRIES = [
1009
+ {
1010
+ code: "GB",
1011
+ name: "United Kingdom",
1012
+ dialCode: "+44",
1013
+ flag: "🇬🇧"
1014
+ },
1015
+ {
1016
+ code: "US",
1017
+ name: "United States",
1018
+ dialCode: "+1",
1019
+ flag: "🇺🇸"
1020
+ },
1021
+ {
1022
+ code: "IE",
1023
+ name: "Ireland",
1024
+ dialCode: "+353",
1025
+ flag: "🇮🇪"
1026
+ },
1027
+ {
1028
+ code: "FR",
1029
+ name: "France",
1030
+ dialCode: "+33",
1031
+ flag: "🇫🇷"
1032
+ },
1033
+ {
1034
+ code: "DE",
1035
+ name: "Germany",
1036
+ dialCode: "+49",
1037
+ flag: "🇩🇪"
1038
+ },
1039
+ {
1040
+ code: "IT",
1041
+ name: "Italy",
1042
+ dialCode: "+39",
1043
+ flag: "🇮🇹"
1044
+ },
1045
+ {
1046
+ code: "ES",
1047
+ name: "Spain",
1048
+ dialCode: "+34",
1049
+ flag: "🇪🇸"
1050
+ },
1051
+ {
1052
+ code: "NL",
1053
+ name: "Netherlands",
1054
+ dialCode: "+31",
1055
+ flag: "🇳🇱"
1056
+ },
1057
+ {
1058
+ code: "BE",
1059
+ name: "Belgium",
1060
+ dialCode: "+32",
1061
+ flag: "🇧🇪"
1062
+ },
1063
+ {
1064
+ code: "PT",
1065
+ name: "Portugal",
1066
+ dialCode: "+351",
1067
+ flag: "🇵🇹"
1068
+ },
1069
+ {
1070
+ code: "CH",
1071
+ name: "Switzerland",
1072
+ dialCode: "+41",
1073
+ flag: "🇨🇭"
1074
+ },
1075
+ {
1076
+ code: "AT",
1077
+ name: "Austria",
1078
+ dialCode: "+43",
1079
+ flag: "🇦🇹"
1080
+ },
1081
+ {
1082
+ code: "SE",
1083
+ name: "Sweden",
1084
+ dialCode: "+46",
1085
+ flag: "🇸🇪"
1086
+ },
1087
+ {
1088
+ code: "NO",
1089
+ name: "Norway",
1090
+ dialCode: "+47",
1091
+ flag: "🇳🇴"
1092
+ },
1093
+ {
1094
+ code: "DK",
1095
+ name: "Denmark",
1096
+ dialCode: "+45",
1097
+ flag: "🇩🇰"
1098
+ },
1099
+ {
1100
+ code: "PL",
1101
+ name: "Poland",
1102
+ dialCode: "+48",
1103
+ flag: "🇵🇱"
1104
+ },
1105
+ {
1106
+ code: "GR",
1107
+ name: "Greece",
1108
+ dialCode: "+30",
1109
+ flag: "🇬🇷"
1110
+ },
1111
+ {
1112
+ code: "CZ",
1113
+ name: "Czech Republic",
1114
+ dialCode: "+420",
1115
+ flag: "🇨🇿"
1116
+ },
1117
+ {
1118
+ code: "RO",
1119
+ name: "Romania",
1120
+ dialCode: "+40",
1121
+ flag: "🇷🇴"
1122
+ },
1123
+ {
1124
+ code: "HU",
1125
+ name: "Hungary",
1126
+ dialCode: "+36",
1127
+ flag: "🇭🇺"
1128
+ },
1129
+ {
1130
+ code: "AU",
1131
+ name: "Australia",
1132
+ dialCode: "+61",
1133
+ flag: "🇦🇺"
1134
+ },
1135
+ {
1136
+ code: "NZ",
1137
+ name: "New Zealand",
1138
+ dialCode: "+64",
1139
+ flag: "🇳🇿"
1140
+ },
1141
+ {
1142
+ code: "CA",
1143
+ name: "Canada",
1144
+ dialCode: "+1",
1145
+ flag: "🇨🇦"
1146
+ },
1147
+ {
1148
+ code: "IN",
1149
+ name: "India",
1150
+ dialCode: "+91",
1151
+ flag: "🇮🇳"
1152
+ },
1153
+ {
1154
+ code: "PK",
1155
+ name: "Pakistan",
1156
+ dialCode: "+92",
1157
+ flag: "🇵🇰"
1158
+ },
1159
+ {
1160
+ code: "BD",
1161
+ name: "Bangladesh",
1162
+ dialCode: "+880",
1163
+ flag: "🇧🇩"
1164
+ },
1165
+ {
1166
+ code: "AE",
1167
+ name: "UAE",
1168
+ dialCode: "+971",
1169
+ flag: "🇦🇪"
1170
+ },
1171
+ {
1172
+ code: "SA",
1173
+ name: "Saudi Arabia",
1174
+ dialCode: "+966",
1175
+ flag: "🇸🇦"
1176
+ },
1177
+ {
1178
+ code: "QA",
1179
+ name: "Qatar",
1180
+ dialCode: "+974",
1181
+ flag: "🇶🇦"
1182
+ },
1183
+ {
1184
+ code: "KW",
1185
+ name: "Kuwait",
1186
+ dialCode: "+965",
1187
+ flag: "🇰🇼"
1188
+ },
1189
+ {
1190
+ code: "SG",
1191
+ name: "Singapore",
1192
+ dialCode: "+65",
1193
+ flag: "🇸🇬"
1194
+ },
1195
+ {
1196
+ code: "MY",
1197
+ name: "Malaysia",
1198
+ dialCode: "+60",
1199
+ flag: "🇲🇾"
1200
+ },
1201
+ {
1202
+ code: "JP",
1203
+ name: "Japan",
1204
+ dialCode: "+81",
1205
+ flag: "🇯🇵"
1206
+ },
1207
+ {
1208
+ code: "KR",
1209
+ name: "South Korea",
1210
+ dialCode: "+82",
1211
+ flag: "🇰🇷"
1212
+ },
1213
+ {
1214
+ code: "CN",
1215
+ name: "China",
1216
+ dialCode: "+86",
1217
+ flag: "🇨🇳"
1218
+ },
1219
+ {
1220
+ code: "HK",
1221
+ name: "Hong Kong",
1222
+ dialCode: "+852",
1223
+ flag: "🇭🇰"
1224
+ },
1225
+ {
1226
+ code: "TW",
1227
+ name: "Taiwan",
1228
+ dialCode: "+886",
1229
+ flag: "🇹🇼"
1230
+ },
1231
+ {
1232
+ code: "TH",
1233
+ name: "Thailand",
1234
+ dialCode: "+66",
1235
+ flag: "🇹🇭"
1236
+ },
1237
+ {
1238
+ code: "PH",
1239
+ name: "Philippines",
1240
+ dialCode: "+63",
1241
+ flag: "🇵🇭"
1242
+ },
1243
+ {
1244
+ code: "VN",
1245
+ name: "Vietnam",
1246
+ dialCode: "+84",
1247
+ flag: "🇻🇳"
1248
+ },
1249
+ {
1250
+ code: "ID",
1251
+ name: "Indonesia",
1252
+ dialCode: "+62",
1253
+ flag: "🇮🇩"
1254
+ },
1255
+ {
1256
+ code: "ZA",
1257
+ name: "South Africa",
1258
+ dialCode: "+27",
1259
+ flag: "🇿🇦"
1260
+ },
1261
+ {
1262
+ code: "NG",
1263
+ name: "Nigeria",
1264
+ dialCode: "+234",
1265
+ flag: "🇳🇬"
1266
+ },
1267
+ {
1268
+ code: "EG",
1269
+ name: "Egypt",
1270
+ dialCode: "+20",
1271
+ flag: "🇪🇬"
1272
+ },
1273
+ {
1274
+ code: "BR",
1275
+ name: "Brazil",
1276
+ dialCode: "+55",
1277
+ flag: "🇧🇷"
1278
+ },
1279
+ {
1280
+ code: "MX",
1281
+ name: "Mexico",
1282
+ dialCode: "+52",
1283
+ flag: "🇲🇽"
1284
+ },
1285
+ {
1286
+ code: "AR",
1287
+ name: "Argentina",
1288
+ dialCode: "+54",
1289
+ flag: "🇦🇷"
1290
+ },
1291
+ {
1292
+ code: "TR",
1293
+ name: "Turkey",
1294
+ dialCode: "+90",
1295
+ flag: "🇹🇷"
1296
+ },
1297
+ {
1298
+ code: "RU",
1299
+ name: "Russia",
1300
+ dialCode: "+7",
1301
+ flag: "🇷🇺"
1302
+ },
1303
+ {
1304
+ code: "IL",
1305
+ name: "Israel",
1306
+ dialCode: "+972",
1307
+ flag: "🇮🇱"
1308
+ }
1309
+ ];
1310
+ function PhoneInput({ className, onChange, value, defaultCountry = "GB", countries = DEFAULT_COUNTRIES, disabled, placeholder = "Phone number", ref, ...props }) {
1311
+ const [isOpen, setIsOpen] = React$1.useState(false);
1312
+ const [searchValue, setSearchValue] = React$1.useState("");
1313
+ const getCountryByCode = React$1.useCallback((code) => countries.find((c) => c.code === code), [countries]);
1314
+ const parseValue = React$1.useCallback((val) => {
1315
+ const valString = val ? String(val) : "";
1316
+ if (!valString) return {
1317
+ country: getCountryByCode(defaultCountry) || countries[0],
1318
+ number: ""
1319
+ };
1320
+ const cleanVal = valString.replace(/\s/g, "");
1321
+ for (const country of countries) if (cleanVal.startsWith(country.dialCode)) return {
1322
+ country,
1323
+ number: cleanVal.slice(country.dialCode.length)
1324
+ };
1325
+ return {
1326
+ country: getCountryByCode(defaultCountry) || countries[0],
1327
+ number: cleanVal.replace(/^\+/, "")
1328
+ };
1329
+ }, [
1330
+ defaultCountry,
1331
+ countries,
1332
+ getCountryByCode
1333
+ ]);
1334
+ const { country, number } = parseValue(value);
1335
+ const [selectedCountry, setSelectedCountry] = React$1.useState(country);
1336
+ React$1.useEffect(() => {
1337
+ setSelectedCountry(parseValue(value).country);
1338
+ }, [value, parseValue]);
1339
+ const handleCountryChange = (newCountry) => {
1340
+ setSelectedCountry(newCountry);
1341
+ setIsOpen(false);
1342
+ if (number) onChange?.(newCountry.dialCode + number);
1343
+ };
1344
+ const handleNumberChange = (e) => {
1345
+ const newNumber = e.target.value.replace(/[^\d]/g, "");
1346
+ if (newNumber) onChange?.(selectedCountry.dialCode + newNumber);
1347
+ else onChange?.("");
1348
+ };
1349
+ return /* @__PURE__ */ jsxs(InputGroup, {
1350
+ className,
1351
+ children: [/* @__PURE__ */ jsx(InputGroupAddon, {
1352
+ align: "inline-start",
1353
+ className: "p-0 overflow-hidden",
1354
+ children: /* @__PURE__ */ jsxs(Popover, {
1355
+ open: isOpen,
1356
+ modal: true,
1357
+ onOpenChange: (open) => {
1358
+ setIsOpen(open);
1359
+ if (open) setSearchValue("");
1360
+ },
1361
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, { render: /* @__PURE__ */ jsxs(Button, {
1362
+ type: "button",
1363
+ variant: "ghost",
1364
+ className: "gap-1.5 rounded-none border-r px-3 focus:z-10 min-w-[90px] h-full",
1365
+ disabled,
1366
+ children: [
1367
+ /* @__PURE__ */ jsx("span", {
1368
+ className: "text-base leading-none",
1369
+ children: selectedCountry.flag
1370
+ }),
1371
+ /* @__PURE__ */ jsx("span", {
1372
+ className: "text-xs text-muted-foreground",
1373
+ children: selectedCountry.dialCode
1374
+ }),
1375
+ /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 opacity-50" })
1376
+ ]
1377
+ }) }), /* @__PURE__ */ jsx(PopoverContent, {
1378
+ className: "w-[280px] p-0",
1379
+ align: "start",
1380
+ children: /* @__PURE__ */ jsxs(Command, { children: [/* @__PURE__ */ jsx(CommandInput, {
1381
+ value: searchValue,
1382
+ onValueChange: setSearchValue,
1383
+ placeholder: "Search country..."
1384
+ }), /* @__PURE__ */ jsx(CommandList, { children: /* @__PURE__ */ jsxs(ScrollArea, {
1385
+ className: "h-64",
1386
+ children: [/* @__PURE__ */ jsx(CommandEmpty, { children: "No country found." }), /* @__PURE__ */ jsx(CommandGroup, { children: countries.filter((c) => c.name.toLowerCase().includes(searchValue.toLowerCase()) || c.dialCode.includes(searchValue) || c.code.toLowerCase().includes(searchValue.toLowerCase())).map((c) => /* @__PURE__ */ jsxs(CommandItem, {
1387
+ className: "gap-2 cursor-pointer",
1388
+ onSelect: () => handleCountryChange(c),
1389
+ value: `${c.name} ${c.code} ${c.dialCode}`,
1390
+ children: [
1391
+ /* @__PURE__ */ jsx("span", {
1392
+ className: "text-base",
1393
+ children: c.flag
1394
+ }),
1395
+ /* @__PURE__ */ jsx("span", {
1396
+ className: "flex-1 text-sm",
1397
+ children: c.name
1398
+ }),
1399
+ /* @__PURE__ */ jsx("span", {
1400
+ className: "text-sm text-muted-foreground",
1401
+ children: c.dialCode
1402
+ })
1403
+ ]
1404
+ }, c.code)) })]
1405
+ }) })] })
1406
+ })]
1407
+ })
1408
+ }), /* @__PURE__ */ jsx(InputGroupInput, {
1409
+ ref,
1410
+ type: "tel",
1411
+ inputMode: "numeric",
1412
+ className: "rounded-s-none",
1413
+ placeholder,
1414
+ value: number,
1415
+ onChange: handleNumberChange,
1416
+ disabled,
1417
+ ...props
1418
+ })]
1419
+ });
1420
+ }
1421
+
1422
+ //#endregion
1423
+ //#region src/components/pill.tsx
1424
+ function Pill({ variant = "secondary", themed = false, className, ...props }) {
1425
+ return /* @__PURE__ */ jsx(Badge, {
1426
+ className: cn("gap-2 rounded-full px-3 py-1.5 font-normal", className),
1427
+ variant,
1428
+ ...props
1429
+ });
1430
+ }
1431
+ function PillAvatar({ fallback, className, src, alt, ...props }) {
1432
+ return /* @__PURE__ */ jsxs(Avatar, {
1433
+ className: cn("-ml-1 h-4 w-4", className),
1434
+ children: [/* @__PURE__ */ jsx(AvatarImage, {
1435
+ src,
1436
+ alt,
1437
+ ...props
1438
+ }), /* @__PURE__ */ jsx(AvatarFallback, { children: fallback })]
1439
+ });
1440
+ }
1441
+ function PillButton({ className, ...props }) {
1442
+ return /* @__PURE__ */ jsx(Button, {
1443
+ className: cn("-my-2 -mr-2 size-6 rounded-full p-0.5 hover:bg-foreground/5", className),
1444
+ size: "icon",
1445
+ variant: "ghost",
1446
+ ...props
1447
+ });
1448
+ }
1449
+ function PillStatus({ children, className, ...props }) {
1450
+ return /* @__PURE__ */ jsx("div", {
1451
+ className: cn("flex items-center gap-2 border-r pr-2 font-medium", className),
1452
+ ...props,
1453
+ children
1454
+ });
1455
+ }
1456
+ function PillIndicator({ variant = "success", pulse = false }) {
1457
+ return /* @__PURE__ */ jsxs("span", {
1458
+ className: "relative flex size-2",
1459
+ children: [pulse && /* @__PURE__ */ jsx("span", { className: cn("absolute inline-flex h-full w-full animate-ping rounded-full opacity-75", variant === "success" && "bg-emerald-400", variant === "error" && "bg-rose-400", variant === "warning" && "bg-amber-400", variant === "info" && "bg-sky-400") }), /* @__PURE__ */ jsx("span", { className: cn("relative inline-flex size-2 rounded-full", variant === "success" && "bg-emerald-500", variant === "error" && "bg-rose-500", variant === "warning" && "bg-amber-500", variant === "info" && "bg-sky-500") })]
1460
+ });
1461
+ }
1462
+ function PillDelta({ className, delta }) {
1463
+ if (!delta) return /* @__PURE__ */ jsx(MinusIcon, { className: cn("size-3 text-muted-foreground", className) });
1464
+ if (delta > 0) return /* @__PURE__ */ jsx(ChevronUpIcon, { className: cn("size-3 text-emerald-500", className) });
1465
+ return /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("size-3 text-rose-500", className) });
1466
+ }
1467
+ function PillIcon({ icon: Icon, className, ...props }) {
1468
+ return /* @__PURE__ */ jsx(Icon, {
1469
+ className: cn("size-3 text-muted-foreground", className),
1470
+ size: 12,
1471
+ ...props
1472
+ });
1473
+ }
1474
+ function PillAvatarGroup({ children, className, ...props }) {
1475
+ return /* @__PURE__ */ jsx("div", {
1476
+ className: cn("-space-x-1 flex items-center", "[&>*:not(:first-of-type)]:mask-[radix-gradient(circle_9px_at_-4px_50%,transparent_99%,white_100%)]", className),
1477
+ ...props,
1478
+ children
1479
+ });
1480
+ }
1481
+
1482
+ //#endregion
1483
+ //#region src/components/tabs-wrapper.tsx
1484
+ const LIST_BASE_CLASS = "flex flex-wrap items-center justify-start gap-1 h-auto rounded-md p-1 shadow-sm transition-colors";
1485
+ const LIST_VARIANTS = {
1486
+ default: "border border-border/50 bg-muted/60 backdrop-blur-sm",
1487
+ primary: "border border-primary/30 bg-primary/10",
1488
+ secondary: "border border-secondary/40 bg-secondary/10",
1489
+ outline: "border border-border bg-background",
1490
+ ghost: "border border-transparent bg-transparent shadow-none",
1491
+ underline: "w-full mb-4 rounded-none border-b border-border/60 bg-transparent p-0 shadow-none gap-6"
1492
+ };
1493
+ const TRIGGER_VARIANTS = {
1494
+ default: "text-muted-foreground hover:bg-muted/40 hover:text-foreground data-active:bg-background data-active:text-foreground data-active:shadow-sm",
1495
+ primary: "text-primary hover:bg-primary/10 hover:text-primary data-active:bg-primary data-active:text-primary-foreground",
1496
+ secondary: "text-secondary-foreground hover:bg-secondary/10 hover:text-secondary-foreground data-active:bg-secondary data-active:text-secondary-foreground",
1497
+ outline: "text-foreground hover:bg-accent/40 hover:text-accent-foreground data-active:bg-accent data-active:text-accent-foreground",
1498
+ ghost: "text-muted-foreground hover:bg-muted/30 hover:text-foreground data-active:bg-muted data-active:text-foreground",
1499
+ underline: "text-muted-foreground rounded-none px-0 py-2 hover:bg-transparent hover:text-primary border-b-2 border-transparent data-active:border-primary data-active:text-primary data-active:shadow-none"
1500
+ };
1501
+ const TabsWrapper = memo(function TabsWrapper({ defaultValue, value, onValueChange, children, className, listClassName, variant = "default", orientation = "horizontal", layout = "default", ...props }) {
1502
+ const isFlexLayout = useMemo(() => layout === "flex" || layout === "sidebar", [layout]);
1503
+ const computedClasses = useMemo(() => ({
1504
+ root: cn("w-full", isFlexLayout && "flex-1 flex flex-col", className),
1505
+ list: cn(LIST_BASE_CLASS, isFlexLayout ? "w-full" : "w-fit", !isFlexLayout && variant !== "underline" && "mb-6", LIST_VARIANTS[variant] ?? LIST_VARIANTS.default, listClassName)
1506
+ }), [
1507
+ isFlexLayout,
1508
+ className,
1509
+ variant,
1510
+ listClassName
1511
+ ]);
1512
+ const triggers = [];
1513
+ const panels = [];
1514
+ Children.forEach(children, (child) => {
1515
+ if (isValidElement(child) && child.type === TabContent) panels.push(child);
1516
+ else triggers.push(child);
1517
+ });
1518
+ return /* @__PURE__ */ jsxs(Tabs, {
1519
+ defaultValue,
1520
+ value,
1521
+ onValueChange,
1522
+ orientation,
1523
+ className: computedClasses.root,
1524
+ ...props,
1525
+ children: [/* @__PURE__ */ jsx(TabsList, {
1526
+ className: computedClasses.list,
1527
+ children: triggers
1528
+ }), panels]
1529
+ });
1530
+ });
1531
+ const TabTrigger = memo(function TabTrigger({ value, children, className, variant = "default", icon, hideTextOnMobile = false, disabled = false, ...props }) {
1532
+ return /* @__PURE__ */ jsxs(TabsTrigger, {
1533
+ value,
1534
+ disabled,
1535
+ className: useMemo(() => cn("flex items-center gap-2 transition-colors duration-200", TRIGGER_VARIANTS[variant] ?? TRIGGER_VARIANTS.default, className), [variant, className]),
1536
+ ...props,
1537
+ children: [icon, hideTextOnMobile ? /* @__PURE__ */ jsx("span", {
1538
+ className: "hidden sm:inline",
1539
+ children
1540
+ }) : children]
1541
+ });
1542
+ });
1543
+ const TabContent = memo(function TabContent({ value, children, className, withScrollArea = false, scrollAreaClassName, padding = true, keepMounted = false, ...props }) {
1544
+ const contentClassName = useMemo(() => cn("space-y-4", padding && !withScrollArea && "mt-6", withScrollArea && "mt-0 h-full", className), [
1545
+ padding,
1546
+ withScrollArea,
1547
+ className
1548
+ ]);
1549
+ const scrollAreaPaddingClassName = useMemo(() => cn(padding && "px-6 py-4"), [padding]);
1550
+ return /* @__PURE__ */ jsx(TabsContent, {
1551
+ value,
1552
+ keepMounted,
1553
+ className: contentClassName,
1554
+ ...props,
1555
+ children: withScrollArea ? /* @__PURE__ */ jsx(ScrollArea, {
1556
+ className: cn("h-full", scrollAreaClassName),
1557
+ children: /* @__PURE__ */ jsx("div", {
1558
+ className: scrollAreaPaddingClassName,
1559
+ children
1560
+ })
1561
+ }) : children
1562
+ });
1563
+ });
1564
+ const DynamicTabs = memo(function DynamicTabs({ tabs = [], defaultValue, value, onValueChange, variant = "default", layout = "default", className, listClassName, listWrapperClassName, contentClassName, scrollable = false, ...props }) {
1565
+ const isFlexLayout = useMemo(() => layout === "flex" || layout === "sidebar", [layout]);
1566
+ const useSheetDefaults = isFlexLayout && scrollable;
1567
+ const computedClasses = useMemo(() => ({
1568
+ root: cn("w-full", isFlexLayout && "flex-1 flex flex-col min-h-0", className),
1569
+ listWrapper: cn("w-full", useSheetDefaults ? "px-0" : "px-6", listWrapperClassName),
1570
+ flexList: cn("flex flex-wrap items-center justify-center gap-1 h-auto", variant === "underline" ? "rounded-none border-b border-border/60 bg-transparent p-0 shadow-none gap-6" : "rounded-md p-1 shadow-sm backdrop-blur-sm", LIST_VARIANTS[variant] ?? LIST_VARIANTS.default, useSheetDefaults && "mb-4 gap-0.5", listClassName),
1571
+ standardList: cn(LIST_BASE_CLASS, variant !== "underline" && "w-fit mb-6", LIST_VARIANTS[variant] ?? LIST_VARIANTS.default, listClassName),
1572
+ contentWrapper: cn(isFlexLayout && "flex-1 min-h-0 overflow-hidden"),
1573
+ flexContent: cn("mt-0 h-full", useSheetDefaults && "px-1", contentClassName),
1574
+ standardContent: cn(isFlexLayout ? "h-full" : "space-y-4 mt-6", contentClassName)
1575
+ }), [
1576
+ isFlexLayout,
1577
+ useSheetDefaults,
1578
+ className,
1579
+ listWrapperClassName,
1580
+ listClassName,
1581
+ variant,
1582
+ contentClassName
1583
+ ]);
1584
+ return /* @__PURE__ */ jsxs(Tabs, {
1585
+ defaultValue,
1586
+ value,
1587
+ onValueChange,
1588
+ className: computedClasses.root,
1589
+ ...props,
1590
+ children: [isFlexLayout ? /* @__PURE__ */ jsx("div", {
1591
+ className: computedClasses.listWrapper,
1592
+ children: /* @__PURE__ */ jsx(TabsList, {
1593
+ className: computedClasses.flexList,
1594
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs(TabTrigger, {
1595
+ value: tab.value,
1596
+ variant,
1597
+ disabled: tab.disabled,
1598
+ className: "justify-center px-3 py-2 text-xs sm:text-sm shrink-0",
1599
+ children: [tab.icon, tab.hideTextOnMobile ? /* @__PURE__ */ jsx("span", {
1600
+ className: "hidden sm:inline",
1601
+ children: tab.label
1602
+ }) : tab.label]
1603
+ }, tab.value))
1604
+ })
1605
+ }) : /* @__PURE__ */ jsx(TabsList, {
1606
+ className: computedClasses.standardList,
1607
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs(TabTrigger, {
1608
+ value: tab.value,
1609
+ variant,
1610
+ disabled: tab.disabled,
1611
+ className: "whitespace-nowrap",
1612
+ children: [tab.icon, tab.hideTextOnMobile ? /* @__PURE__ */ jsx("span", {
1613
+ className: "hidden sm:inline text-sm",
1614
+ children: tab.label
1615
+ }) : /* @__PURE__ */ jsx("span", {
1616
+ className: "text-sm",
1617
+ children: tab.label
1618
+ })]
1619
+ }, tab.value))
1620
+ }), /* @__PURE__ */ jsx("div", {
1621
+ className: computedClasses.contentWrapper,
1622
+ children: isFlexLayout && scrollable ? /* @__PURE__ */ jsx(ScrollArea, {
1623
+ className: "h-full w-full",
1624
+ children: tabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, {
1625
+ value: tab.value,
1626
+ className: computedClasses.flexContent,
1627
+ children: tab.content
1628
+ }, tab.value))
1629
+ }) : tabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, {
1630
+ value: tab.value,
1631
+ className: computedClasses.standardContent,
1632
+ children: tab.content
1633
+ }, tab.value))
1634
+ })]
1635
+ });
1636
+ });
1637
+
1638
+ //#endregion
1639
+ //#region src/components/responsive-split-layout.tsx
1640
+ function ResponsiveSplitLayout({ leftPanel, rightPanel, className, leftPanelClassName, rightPanelClassName, variant = "default", desktopVariant, mobileVariant, defaultLayout = [50, 50], minSizes = [20, 20], rightPanelWidth = 400, persistLayoutKey, mobileBreakpoint = "md", forceMobile = false, forceDesktop = false }) {
1641
+ const [mobileView, setMobileView] = useState("left");
1642
+ const isMobileMedia = useMediaQuery(`(max-width: ${{
1643
+ sm: 640,
1644
+ md: 768,
1645
+ lg: 1024,
1646
+ xl: 1280
1647
+ }[mobileBreakpoint] - 1}px)`, false);
1648
+ const isMobile = forceDesktop ? false : forceMobile ? true : isMobileMedia;
1649
+ const effectiveMobileVariant = mobileVariant ?? variant;
1650
+ const effectiveDesktopVariant = desktopVariant ?? variant;
1651
+ if (isMobile && effectiveMobileVariant === "tabs") {
1652
+ const tabs = [{
1653
+ value: "left",
1654
+ label: /* @__PURE__ */ jsxs("div", {
1655
+ className: "flex items-center gap-2",
1656
+ children: [leftPanel.icon, leftPanel.title || "Left"]
1657
+ }),
1658
+ content: /* @__PURE__ */ jsx("div", {
1659
+ className: cn("h-full overflow-y-auto", leftPanelClassName),
1660
+ children: leftPanel.content
1661
+ })
1662
+ }, {
1663
+ value: "right",
1664
+ label: /* @__PURE__ */ jsxs("div", {
1665
+ className: "flex items-center gap-2",
1666
+ children: [
1667
+ rightPanel.icon,
1668
+ rightPanel.title || "Right",
1669
+ rightPanel.badge && /* @__PURE__ */ jsx("span", {
1670
+ className: "ml-1 bg-primary text-primary-foreground text-xs rounded-full h-5 w-5 flex items-center justify-center",
1671
+ children: rightPanel.badge
1672
+ })
1673
+ ]
1674
+ }),
1675
+ content: /* @__PURE__ */ jsx("div", {
1676
+ className: cn("h-full overflow-y-auto", rightPanelClassName),
1677
+ children: rightPanel.content
1678
+ })
1679
+ }];
1680
+ return /* @__PURE__ */ jsx("div", {
1681
+ className: cn("h-full flex flex-col", className),
1682
+ children: /* @__PURE__ */ jsx(DynamicTabs, {
1683
+ tabs,
1684
+ defaultValue: "left",
1685
+ value: mobileView,
1686
+ onValueChange: (val) => setMobileView(val),
1687
+ variant: "default",
1688
+ layout: "flex",
1689
+ className: "h-full",
1690
+ listWrapperClassName: "px-4 py-2 flex-shrink-0",
1691
+ contentClassName: "mt-0 flex-1 min-h-0"
1692
+ })
1693
+ });
1694
+ }
1695
+ if (isMobile) {
1696
+ const showLeft = mobileView === "left";
1697
+ const showRight = mobileView === "right";
1698
+ return /* @__PURE__ */ jsxs("div", {
1699
+ className: cn("flex flex-col h-full", className),
1700
+ children: [/* @__PURE__ */ jsxs("div", {
1701
+ className: "flex-1 overflow-hidden",
1702
+ children: [/* @__PURE__ */ jsx("div", {
1703
+ className: cn("h-full", !showLeft && "hidden", leftPanelClassName),
1704
+ children: leftPanel.content
1705
+ }), /* @__PURE__ */ jsx("div", {
1706
+ className: cn("h-full", !showRight && "hidden", rightPanelClassName),
1707
+ children: rightPanel.content
1708
+ })]
1709
+ }), /* @__PURE__ */ jsx("div", {
1710
+ className: "border-t p-4 bg-background",
1711
+ children: /* @__PURE__ */ jsxs("div", {
1712
+ className: "flex items-center justify-between max-w-md mx-auto",
1713
+ children: [/* @__PURE__ */ jsxs(Button, {
1714
+ variant: mobileView === "left" ? "default" : "outline",
1715
+ onClick: () => setMobileView("left"),
1716
+ className: "flex-1 mr-2",
1717
+ children: [
1718
+ mobileView === "right" && /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4 mr-2" }),
1719
+ leftPanel.icon,
1720
+ /* @__PURE__ */ jsx("span", {
1721
+ className: "ml-2",
1722
+ children: leftPanel.title || "Left"
1723
+ })
1724
+ ]
1725
+ }), /* @__PURE__ */ jsxs(Button, {
1726
+ variant: mobileView === "right" ? "default" : "outline",
1727
+ onClick: () => setMobileView("right"),
1728
+ className: "flex-1 ml-2 relative",
1729
+ children: [
1730
+ /* @__PURE__ */ jsx("span", {
1731
+ className: "mr-2",
1732
+ children: rightPanel.title || "Right"
1733
+ }),
1734
+ rightPanel.icon,
1735
+ mobileView === "left" && /* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4 ml-2" }),
1736
+ rightPanel.badge && /* @__PURE__ */ jsx("span", {
1737
+ className: "absolute -top-2 -right-2 bg-primary text-primary-foreground text-xs rounded-full h-6 w-6 flex items-center justify-center",
1738
+ children: rightPanel.badge
1739
+ })
1740
+ ]
1741
+ })]
1742
+ })
1743
+ })]
1744
+ });
1745
+ }
1746
+ if (effectiveDesktopVariant === "fixed") return /* @__PURE__ */ jsxs("div", {
1747
+ className: cn("flex h-full", className),
1748
+ children: [/* @__PURE__ */ jsx("div", {
1749
+ className: cn("flex-1 overflow-auto border-r", leftPanelClassName),
1750
+ children: leftPanel.content
1751
+ }), /* @__PURE__ */ jsx("div", {
1752
+ className: cn("overflow-auto", rightPanelClassName),
1753
+ style: {
1754
+ width: rightPanelWidth,
1755
+ minWidth: rightPanelWidth,
1756
+ flexShrink: 0
1757
+ },
1758
+ children: rightPanel.content
1759
+ })]
1760
+ });
1761
+ return /* @__PURE__ */ jsxs(ResizablePanelGroup, {
1762
+ direction: "horizontal",
1763
+ className: cn("h-full", className),
1764
+ autoSaveId: persistLayoutKey,
1765
+ children: [
1766
+ /* @__PURE__ */ jsx(ResizablePanel, {
1767
+ defaultSize: defaultLayout[0],
1768
+ minSize: minSizes[0],
1769
+ children: /* @__PURE__ */ jsx("div", {
1770
+ className: cn("h-full overflow-auto", leftPanelClassName),
1771
+ children: leftPanel.content
1772
+ })
1773
+ }),
1774
+ /* @__PURE__ */ jsx(ResizableHandle, { withHandle: true }),
1775
+ /* @__PURE__ */ jsx(ResizablePanel, {
1776
+ defaultSize: defaultLayout[1],
1777
+ minSize: minSizes[1],
1778
+ children: /* @__PURE__ */ jsx("div", {
1779
+ className: cn("h-full overflow-auto", rightPanelClassName),
1780
+ children: rightPanel.content
1781
+ })
1782
+ })
1783
+ ]
1784
+ });
1785
+ }
1786
+
1787
+ //#endregion
1788
+ //#region src/components/status-banner.tsx
1789
+ const VARIANT_MAP = {
1790
+ info: {
1791
+ icon: Info,
1792
+ bg: "bg-blue-50 dark:bg-blue-950/30",
1793
+ border: "border-blue-200 dark:border-blue-800",
1794
+ text: "text-blue-800 dark:text-blue-200",
1795
+ iconColor: "text-blue-500 dark:text-blue-400"
1796
+ },
1797
+ warning: {
1798
+ icon: AlertTriangle,
1799
+ bg: "bg-amber-50 dark:bg-amber-950/30",
1800
+ border: "border-amber-200 dark:border-amber-800",
1801
+ text: "text-amber-800 dark:text-amber-200",
1802
+ iconColor: "text-amber-500 dark:text-amber-400"
1803
+ },
1804
+ success: {
1805
+ icon: CheckCircle2,
1806
+ bg: "bg-emerald-50 dark:bg-emerald-950/30",
1807
+ border: "border-emerald-200 dark:border-emerald-800",
1808
+ text: "text-emerald-800 dark:text-emerald-200",
1809
+ iconColor: "text-emerald-500 dark:text-emerald-400"
1810
+ },
1811
+ error: {
1812
+ icon: AlertCircle,
1813
+ bg: "bg-red-50 dark:bg-red-950/30",
1814
+ border: "border-red-200 dark:border-red-800",
1815
+ text: "text-red-800 dark:text-red-200",
1816
+ iconColor: "text-red-500 dark:text-red-400"
1817
+ }
1818
+ };
1819
+ /**
1820
+ * StatusBanner — A persistent info/warning/success/error banner.
1821
+ *
1822
+ * @example
1823
+ * ```tsx
1824
+ * <StatusBanner variant="warning" dismissible>
1825
+ * Your trial expires in 3 days. <a href="/pricing">Upgrade now</a>
1826
+ * </StatusBanner>
1827
+ *
1828
+ * <StatusBanner variant="success" action={<Button size="sm">View</Button>}>
1829
+ * Your project was deployed successfully.
1830
+ * </StatusBanner>
1831
+ * ```
1832
+ */
1833
+ function StatusBanner({ variant = "info", children, icon: CustomIcon, dismissible = false, onDismiss, action, className }) {
1834
+ const [dismissed, setDismissed] = React$1.useState(false);
1835
+ if (dismissed) return null;
1836
+ const config = VARIANT_MAP[variant];
1837
+ const Icon = CustomIcon || config.icon;
1838
+ const handleDismiss = () => {
1839
+ setDismissed(true);
1840
+ onDismiss?.();
1841
+ };
1842
+ return /* @__PURE__ */ jsxs("div", {
1843
+ role: "alert",
1844
+ className: cn("flex items-center gap-3 rounded-lg border px-4 py-3", config.bg, config.border, config.text, className),
1845
+ children: [
1846
+ /* @__PURE__ */ jsx(Icon, {
1847
+ className: cn("h-4 w-4 shrink-0", config.iconColor),
1848
+ strokeWidth: 2
1849
+ }),
1850
+ /* @__PURE__ */ jsx("div", {
1851
+ className: "flex-1 min-w-0 text-sm",
1852
+ children
1853
+ }),
1854
+ action && /* @__PURE__ */ jsx("div", {
1855
+ className: "shrink-0",
1856
+ children: action
1857
+ }),
1858
+ dismissible && /* @__PURE__ */ jsxs(Button, {
1859
+ variant: "ghost",
1860
+ size: "icon",
1861
+ className: cn("h-6 w-6 shrink-0 hover:bg-transparent opacity-60 hover:opacity-100", config.text),
1862
+ onClick: handleDismiss,
1863
+ children: [/* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ jsx("span", {
1864
+ className: "sr-only",
1865
+ children: "Dismiss"
1866
+ })]
1867
+ })
1868
+ ]
1869
+ });
1870
+ }
1871
+
1872
+ //#endregion
1873
+ //#region src/components/stepper.tsx
1874
+ function normalizeStep(step) {
1875
+ return typeof step === "string" ? { label: step } : step;
1876
+ }
1877
+ const StepCircle = React$1.memo(function StepCircle({ index, isCompleted, isActive, icon, variant }) {
1878
+ const size = variant === "compact" ? "h-7 w-7" : "h-8 w-8";
1879
+ const iconSize = variant === "compact" ? "h-3.5 w-3.5" : "h-4 w-4";
1880
+ return /* @__PURE__ */ jsx("span", {
1881
+ className: cn("relative flex items-center justify-center rounded-full text-xs font-semibold shrink-0 transition-all duration-200", size, isCompleted ? "bg-primary text-primary-foreground" : isActive ? "bg-primary text-primary-foreground ring-2 ring-primary/20 ring-offset-2 ring-offset-background" : "border-2 border-muted-foreground/25 bg-background text-muted-foreground"),
1882
+ children: isCompleted ? /* @__PURE__ */ jsx(Check, {
1883
+ className: iconSize,
1884
+ strokeWidth: 3
1885
+ }) : icon || index + 1
1886
+ });
1887
+ });
1888
+ const StepConnector = React$1.memo(function StepConnector({ isCompleted, isVertical }) {
1889
+ if (isVertical) return /* @__PURE__ */ jsx("div", {
1890
+ className: "flex justify-center w-8 py-1",
1891
+ children: /* @__PURE__ */ jsx("div", { className: cn("w-px h-6 transition-colors duration-200", isCompleted ? "bg-primary" : "bg-border") })
1892
+ });
1893
+ return /* @__PURE__ */ jsx("div", {
1894
+ className: "flex-1 flex items-center min-w-4 mt-4",
1895
+ children: /* @__PURE__ */ jsx("div", { className: cn("h-px w-full transition-colors duration-200", isCompleted ? "bg-primary" : "bg-border") })
1896
+ });
1897
+ });
1898
+ function HorizontalStepper({ steps, currentStep, variant, onStepClick }) {
1899
+ const activeRef = React$1.useRef(null);
1900
+ const navRef = React$1.useRef(null);
1901
+ React$1.useEffect(() => {
1902
+ if (activeRef.current && navRef.current) activeRef.current.scrollIntoView({
1903
+ behavior: "smooth",
1904
+ block: "nearest",
1905
+ inline: "center"
1906
+ });
1907
+ }, [currentStep]);
1908
+ return /* @__PURE__ */ jsx("nav", {
1909
+ ref: navRef,
1910
+ "aria-label": "Progress",
1911
+ role: "list",
1912
+ className: "flex items-start w-full overflow-x-auto [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden pb-1",
1913
+ children: steps.map((step, index) => {
1914
+ const isCompleted = index < currentStep;
1915
+ const isActive = index === currentStep;
1916
+ const isClickable = isCompleted && !!onStepClick;
1917
+ const isLast = index === steps.length - 1;
1918
+ return /* @__PURE__ */ jsxs(React$1.Fragment, { children: [/* @__PURE__ */ jsx("div", {
1919
+ ref: isActive ? activeRef : void 0,
1920
+ role: "listitem",
1921
+ "aria-current": isActive ? "step" : void 0,
1922
+ className: cn("flex flex-col items-center text-center shrink-0"),
1923
+ style: { minWidth: variant === "compact" ? 48 : 64 },
1924
+ children: /* @__PURE__ */ jsxs("button", {
1925
+ type: "button",
1926
+ disabled: !isClickable,
1927
+ onClick: () => isClickable && onStepClick(index),
1928
+ className: cn("flex flex-col items-center gap-1.5 group", isClickable ? "cursor-pointer" : "cursor-default"),
1929
+ children: [/* @__PURE__ */ jsx(StepCircle, {
1930
+ index,
1931
+ isCompleted,
1932
+ isActive,
1933
+ icon: step.icon,
1934
+ variant
1935
+ }), /* @__PURE__ */ jsxs("div", {
1936
+ className: "max-w-[5.5rem] sm:max-w-[7rem]",
1937
+ children: [
1938
+ /* @__PURE__ */ jsx("p", {
1939
+ className: cn("text-xs font-medium leading-tight truncate", isActive || isCompleted ? "text-foreground" : "text-muted-foreground"),
1940
+ children: step.label
1941
+ }),
1942
+ step.optional && /* @__PURE__ */ jsx("span", {
1943
+ className: "text-[10px] text-muted-foreground font-normal",
1944
+ children: "optional"
1945
+ }),
1946
+ step.description && variant !== "compact" && /* @__PURE__ */ jsx("p", {
1947
+ className: "text-[10px] text-muted-foreground mt-0.5 leading-tight truncate hidden sm:block",
1948
+ children: step.description
1949
+ })
1950
+ ]
1951
+ })]
1952
+ })
1953
+ }), !isLast && /* @__PURE__ */ jsx(StepConnector, {
1954
+ isCompleted,
1955
+ isVertical: false
1956
+ })] }, step.label);
1957
+ })
1958
+ });
1959
+ }
1960
+ function VerticalStepper({ steps, currentStep, variant, onStepClick }) {
1961
+ return /* @__PURE__ */ jsx("nav", {
1962
+ "aria-label": "Progress",
1963
+ role: "list",
1964
+ className: "flex flex-col",
1965
+ children: steps.map((step, index) => {
1966
+ const isCompleted = index < currentStep;
1967
+ const isActive = index === currentStep;
1968
+ const isClickable = isCompleted && !!onStepClick;
1969
+ const isLast = index === steps.length - 1;
1970
+ return /* @__PURE__ */ jsxs(React$1.Fragment, { children: [/* @__PURE__ */ jsx("div", {
1971
+ role: "listitem",
1972
+ "aria-current": isActive ? "step" : void 0,
1973
+ className: "flex items-start gap-3",
1974
+ children: /* @__PURE__ */ jsxs("button", {
1975
+ type: "button",
1976
+ disabled: !isClickable,
1977
+ onClick: () => isClickable && onStepClick(index),
1978
+ className: cn("flex items-center gap-3", isClickable ? "cursor-pointer" : "cursor-default"),
1979
+ children: [/* @__PURE__ */ jsx(StepCircle, {
1980
+ index,
1981
+ isCompleted,
1982
+ isActive,
1983
+ icon: step.icon,
1984
+ variant
1985
+ }), /* @__PURE__ */ jsxs("div", {
1986
+ className: "text-left",
1987
+ children: [/* @__PURE__ */ jsxs("p", {
1988
+ className: cn("text-sm font-medium leading-tight", isActive || isCompleted ? "text-foreground" : "text-muted-foreground"),
1989
+ children: [step.label, step.optional && /* @__PURE__ */ jsx("span", {
1990
+ className: "ml-1 text-xs text-muted-foreground font-normal",
1991
+ children: "(optional)"
1992
+ })]
1993
+ }), step.description && variant !== "compact" && /* @__PURE__ */ jsx("p", {
1994
+ className: "text-xs text-muted-foreground mt-0.5",
1995
+ children: step.description
1996
+ })]
1997
+ })]
1998
+ })
1999
+ }), !isLast && /* @__PURE__ */ jsx(StepConnector, {
2000
+ isCompleted,
2001
+ isVertical: true
2002
+ })] }, step.label);
2003
+ })
2004
+ });
2005
+ }
2006
+ /**
2007
+ * Stepper — Multi-step progress indicator
2008
+ *
2009
+ * Features:
2010
+ * - Horizontal layout: circles in a row with labels below, proper connectors
2011
+ * - Vertical layout: circles on the left with labels to the right
2012
+ * - Compact variant for tight spaces
2013
+ * - Handles many steps gracefully without scrollbars
2014
+ * - Clickable completed steps for navigation
2015
+ * - Accessible: role="list", aria-current="step"
2016
+ *
2017
+ * @example Basic
2018
+ * ```tsx
2019
+ * const [step, setStep] = useState(0);
2020
+ *
2021
+ * <Stepper steps={["Details", "Config", "Review"]} currentStep={step}>
2022
+ * <StepContent step={0} currentStep={step}>
2023
+ * <DetailsForm onNext={() => setStep(1)} />
2024
+ * </StepContent>
2025
+ * </Stepper>
2026
+ * ```
2027
+ *
2028
+ * @example With step objects
2029
+ * ```tsx
2030
+ * <Stepper
2031
+ * steps={[
2032
+ * { label: "Account", description: "Set up your account" },
2033
+ * { label: "Profile", description: "Add your details", optional: true },
2034
+ * { label: "Complete", description: "Review and submit" },
2035
+ * ]}
2036
+ * currentStep={1}
2037
+ * onStepClick={(i) => setStep(i)}
2038
+ * />
2039
+ * ```
2040
+ */
2041
+ function Stepper({ steps, currentStep, variant = "default", orientation = "horizontal", className, onStepClick, children, ...props }) {
2042
+ const normalizedSteps = steps.map(normalizeStep);
2043
+ const isVertical = orientation === "vertical";
2044
+ return /* @__PURE__ */ jsxs("div", {
2045
+ className: cn("w-full", className),
2046
+ ...props,
2047
+ children: [isVertical ? /* @__PURE__ */ jsx(VerticalStepper, {
2048
+ steps: normalizedSteps,
2049
+ currentStep,
2050
+ variant,
2051
+ onStepClick
2052
+ }) : /* @__PURE__ */ jsx(HorizontalStepper, {
2053
+ steps: normalizedSteps,
2054
+ currentStep,
2055
+ variant,
2056
+ onStepClick
2057
+ }), children && /* @__PURE__ */ jsx("div", {
2058
+ className: cn("mt-6", isVertical && "ml-11"),
2059
+ children
2060
+ })]
2061
+ });
2062
+ }
2063
+ /**
2064
+ * StepContent — Renders content for a specific step.
2065
+ * Only visible when `step === currentStep`.
2066
+ *
2067
+ * @example
2068
+ * ```tsx
2069
+ * <StepContent step={0} currentStep={current}>
2070
+ * <MyForm />
2071
+ * </StepContent>
2072
+ * ```
2073
+ */
2074
+ function StepContent({ step, currentStep, children, className, keepMounted = false }) {
2075
+ const isActive = step === currentStep;
2076
+ if (!isActive && !keepMounted) return null;
2077
+ return /* @__PURE__ */ jsx("div", {
2078
+ className: cn(className),
2079
+ hidden: !isActive,
2080
+ role: "tabpanel",
2081
+ "aria-label": `Step ${step + 1}`,
2082
+ children
2083
+ });
2084
+ }
2085
+
2086
+ //#endregion
2087
+ //#region src/components/table-wrapper.tsx
2088
+ function TableWrapper({ title, description, icon, children, columns, data, renderRow, emptyState, className, tableClassName, maxHeight = "500px", ...props }) {
2089
+ const hasData = data && data.length > 0;
2090
+ const defaultEmptyState = emptyState || {
2091
+ icon,
2092
+ title: "No data available",
2093
+ description: "There are no items to display"
2094
+ };
2095
+ return /* @__PURE__ */ jsxs("div", {
2096
+ className: cn("space-y-4", className),
2097
+ ...props,
2098
+ children: [(title || description) && /* @__PURE__ */ jsxs("div", {
2099
+ className: "space-y-1",
2100
+ children: [title && /* @__PURE__ */ jsx("h3", {
2101
+ className: "text-lg font-semibold",
2102
+ children: title
2103
+ }), description && /* @__PURE__ */ jsx("p", {
2104
+ className: "text-sm text-muted-foreground",
2105
+ children: description
2106
+ })]
2107
+ }), !hasData ? /* @__PURE__ */ jsxs("div", {
2108
+ className: "flex flex-col items-center justify-center h-48 text-muted-foreground border rounded-lg",
2109
+ children: [
2110
+ defaultEmptyState.icon && /* @__PURE__ */ jsx("div", {
2111
+ className: "h-12 w-12 mb-4 opacity-50",
2112
+ children: defaultEmptyState.icon
2113
+ }),
2114
+ /* @__PURE__ */ jsx("p", {
2115
+ className: "text-lg",
2116
+ children: defaultEmptyState.title
2117
+ }),
2118
+ defaultEmptyState.description && /* @__PURE__ */ jsx("p", {
2119
+ className: "text-sm",
2120
+ children: defaultEmptyState.description
2121
+ })
2122
+ ]
2123
+ }) : /* @__PURE__ */ jsx("div", {
2124
+ className: cn("relative overflow-auto border rounded-lg", maxHeight && `max-h-[${maxHeight}]`),
2125
+ children: /* @__PURE__ */ jsxs(Table, {
2126
+ className: tableClassName,
2127
+ children: [columns && /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { children: columns.map((column, index) => /* @__PURE__ */ jsx(TableHead, {
2128
+ className: cn(column.className),
2129
+ children: column.header
2130
+ }, `table-column-head-${column.key ?? column.header ?? index}`)) }) }), /* @__PURE__ */ jsx(TableBody, { children: data?.map((item, index) => renderRow ? renderRow(item, index) : /* @__PURE__ */ jsx(TableRow, { children }, `table-row-${index}`)) })]
2131
+ })
2132
+ })]
2133
+ });
2134
+ }
2135
+ function SimpleTable({ title, data, columns, emptyState, className, ...props }) {
2136
+ const renderRow = (item, index) => /* @__PURE__ */ jsx(TableRow, { children: columns.map((column, colIndex) => /* @__PURE__ */ jsx(TableCell, {
2137
+ className: column.cellClassName,
2138
+ children: column.render ? column.render(item, index) : item[column.key]
2139
+ }, `simple-table-cell-${column.key ?? column.header ?? colIndex}`)) }, `simple-table-row-${index}`);
2140
+ return /* @__PURE__ */ jsx(TableWrapper, {
2141
+ title,
2142
+ data,
2143
+ columns,
2144
+ renderRow,
2145
+ emptyState,
2146
+ className,
2147
+ ...props
2148
+ });
2149
+ }
2150
+
2151
+ //#endregion
2152
+ //#region src/components/thumbnail.tsx
2153
+ const aspectRatios = {
2154
+ square: "aspect-square",
2155
+ video: "aspect-video",
2156
+ portrait: "aspect-[3/4]"
2157
+ };
2158
+ const sizes = {
2159
+ small: "w-16 h-16",
2160
+ medium: "w-32 h-32",
2161
+ large: "w-48 h-48",
2162
+ full: "w-full h-full"
2163
+ };
2164
+ function Thumbnail({ src, alt, aspect = "square", size = "medium", className, fallback = "/placeholder.svg", onClick }) {
2165
+ const sizeClass = className?.includes("w-") ? "" : sizes[size];
2166
+ return /* @__PURE__ */ jsx("div", {
2167
+ className: cn("relative rounded-md overflow-hidden", aspectRatios[aspect], sizeClass, onClick && "cursor-pointer", className),
2168
+ onClick,
2169
+ children: /* @__PURE__ */ jsx(Image, {
2170
+ src: src || fallback,
2171
+ alt: alt || "Thumbnail",
2172
+ fill: true,
2173
+ className: "object-cover",
2174
+ sizes: getSizes(size)
2175
+ })
2176
+ });
2177
+ }
2178
+ const getSizes = (size) => {
2179
+ switch (size) {
2180
+ case "small": return "64px";
2181
+ case "medium": return "128px";
2182
+ case "large": return "192px";
2183
+ case "full": return "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw";
2184
+ default: return "128px";
2185
+ }
2186
+ };
2187
+
2188
+ //#endregion
2189
+ //#region src/components/tooltip-wrapper.tsx
2190
+ function TooltipWrapper({ children, content, side = "top", align = "center", delay = 700, sideOffset = 4, className, contentClassName, disabled = false, ...props }) {
2191
+ if (disabled || !content) return /* @__PURE__ */ jsx(Fragment, { children });
2192
+ return /* @__PURE__ */ jsxs(Tooltip, {
2193
+ delay,
2194
+ ...props,
2195
+ children: [/* @__PURE__ */ jsx(TooltipTrigger, {
2196
+ className,
2197
+ render: children
2198
+ }), /* @__PURE__ */ jsx(TooltipContent, {
2199
+ side,
2200
+ align,
2201
+ sideOffset,
2202
+ className: cn(contentClassName),
2203
+ children: content
2204
+ })]
2205
+ });
2206
+ }
2207
+ function ButtonTooltip({ children, tooltip, variant = "outline", size = "icon", className, ...props }) {
2208
+ return /* @__PURE__ */ jsx(TooltipWrapper, {
2209
+ content: tooltip,
2210
+ ...props,
2211
+ children
2212
+ });
2213
+ }
2214
+ function IconTooltip({ icon, tooltip, className, iconClassName, size = 16, ...props }) {
2215
+ return /* @__PURE__ */ jsx(TooltipWrapper, {
2216
+ content: tooltip,
2217
+ className,
2218
+ ...props,
2219
+ children: /* @__PURE__ */ jsx("div", {
2220
+ className: cn("cursor-pointer", iconClassName),
2221
+ children: typeof icon === "string" ? /* @__PURE__ */ jsx("span", {
2222
+ style: { fontSize: size },
2223
+ children: icon
2224
+ }) : icon
2225
+ })
2226
+ });
2227
+ }
2228
+ function InfoTooltip({ tooltip, className, size = 16, ...props }) {
2229
+ return /* @__PURE__ */ jsx(TooltipWrapper, {
2230
+ content: tooltip,
2231
+ className: cn("inline-flex items-center", className),
2232
+ ...props,
2233
+ children: /* @__PURE__ */ jsx("div", {
2234
+ className: "rounded-full bg-muted text-muted-foreground hover:bg-muted/80 transition-colors cursor-help inline-flex items-center justify-center",
2235
+ style: {
2236
+ width: size,
2237
+ height: size,
2238
+ fontSize: size * .6
2239
+ },
2240
+ children: "?"
2241
+ })
2242
+ });
2243
+ }
2244
+ function ActionTooltip({ children, tooltip, action, variant = "ghost", size = "sm", className, ...props }) {
2245
+ return /* @__PURE__ */ jsx(TooltipWrapper, {
2246
+ content: tooltip,
2247
+ ...props,
2248
+ children: /* @__PURE__ */ jsx("button", {
2249
+ onClick: action,
2250
+ className: cn("inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "disabled:opacity-50 disabled:pointer-events-none", variant === "ghost" && "hover:bg-accent hover:text-accent-foreground", variant === "outline" && "border border-input hover:bg-accent hover:text-accent-foreground", size === "sm" && "h-8 px-2", size === "icon" && "h-8 w-8", className),
2251
+ children
2252
+ })
2253
+ });
2254
+ }
2255
+
2256
+ //#endregion
2257
+ //#region src/components/timeline.tsx
2258
+ const STATUS_CONFIG = {
2259
+ default: {
2260
+ dotClass: "bg-muted-foreground/20 text-muted-foreground",
2261
+ lineClass: "bg-border",
2262
+ defaultIcon: Circle
2263
+ },
2264
+ success: {
2265
+ dotClass: "bg-green-500/20 text-green-600 dark:text-green-400",
2266
+ lineClass: "bg-green-500/30",
2267
+ defaultIcon: Check
2268
+ },
2269
+ error: {
2270
+ dotClass: "bg-red-500/20 text-red-600 dark:text-red-400",
2271
+ lineClass: "bg-red-500/30",
2272
+ defaultIcon: X
2273
+ },
2274
+ warning: {
2275
+ dotClass: "bg-yellow-500/20 text-yellow-600 dark:text-yellow-400",
2276
+ lineClass: "bg-yellow-500/30",
2277
+ defaultIcon: AlertTriangle
2278
+ },
2279
+ pending: {
2280
+ dotClass: "bg-muted text-muted-foreground animate-pulse",
2281
+ lineClass: "bg-border border-dashed",
2282
+ defaultIcon: Circle
2283
+ },
2284
+ active: {
2285
+ dotClass: "bg-primary/20 text-primary ring-2 ring-primary/30",
2286
+ lineClass: "bg-primary/30",
2287
+ defaultIcon: Circle
2288
+ }
2289
+ };
2290
+ const SIZE_CONFIG = {
2291
+ sm: {
2292
+ dot: "h-6 w-6",
2293
+ icon: "h-3 w-3",
2294
+ gap: "gap-3",
2295
+ text: "text-xs"
2296
+ },
2297
+ default: {
2298
+ dot: "h-8 w-8",
2299
+ icon: "h-4 w-4",
2300
+ gap: "gap-4",
2301
+ text: "text-sm"
2302
+ },
2303
+ lg: {
2304
+ dot: "h-10 w-10",
2305
+ icon: "h-5 w-5",
2306
+ gap: "gap-5",
2307
+ text: "text-base"
2308
+ }
2309
+ };
2310
+ function Timeline({ items, orientation = "vertical", size = "default", showConnectors = true, reverse = false, className }) {
2311
+ const sizeConfig = SIZE_CONFIG[size];
2312
+ const orderedItems = reverse ? [...items].reverse() : items;
2313
+ if (orientation === "horizontal") return /* @__PURE__ */ jsx("div", {
2314
+ className: cn("flex overflow-x-auto", sizeConfig.gap, className),
2315
+ children: orderedItems.map((item, index) => /* @__PURE__ */ jsx(HorizontalTimelineItem, {
2316
+ item,
2317
+ isLast: index === orderedItems.length - 1,
2318
+ showConnector: showConnectors,
2319
+ size
2320
+ }, index))
2321
+ });
2322
+ return /* @__PURE__ */ jsx("div", {
2323
+ className: cn("relative", className),
2324
+ children: orderedItems.map((item, index) => /* @__PURE__ */ jsx(VerticalTimelineItem, {
2325
+ item,
2326
+ isLast: index === orderedItems.length - 1,
2327
+ showConnector: showConnectors,
2328
+ size
2329
+ }, index))
2330
+ });
2331
+ }
2332
+ function VerticalTimelineItem({ item, isLast, showConnector, size }) {
2333
+ const config = STATUS_CONFIG[item.status || "default"];
2334
+ const sizeConfig = SIZE_CONFIG[size];
2335
+ const renderIcon = () => {
2336
+ if (React$1.isValidElement(item.icon)) return item.icon;
2337
+ return /* @__PURE__ */ jsx(item.icon || config.defaultIcon, { className: sizeConfig.icon });
2338
+ };
2339
+ return /* @__PURE__ */ jsxs("div", {
2340
+ className: cn("flex", sizeConfig.gap, "pb-6 last:pb-0"),
2341
+ children: [/* @__PURE__ */ jsxs("div", {
2342
+ className: "flex flex-col items-center shrink-0",
2343
+ children: [/* @__PURE__ */ jsx("div", {
2344
+ className: cn("flex items-center justify-center rounded-full shrink-0", sizeConfig.dot, config.dotClass),
2345
+ children: renderIcon()
2346
+ }), showConnector && !isLast && /* @__PURE__ */ jsx("div", { className: cn("w-0.5 flex-1 mt-2", config.lineClass) })]
2347
+ }), /* @__PURE__ */ jsxs("div", {
2348
+ className: "min-w-0 flex-1 pt-0.5 pb-2",
2349
+ children: [
2350
+ /* @__PURE__ */ jsxs("div", {
2351
+ className: "flex items-start justify-between gap-2",
2352
+ children: [/* @__PURE__ */ jsxs("div", {
2353
+ className: "min-w-0",
2354
+ children: [/* @__PURE__ */ jsx("p", {
2355
+ className: cn("font-medium leading-tight", sizeConfig.text),
2356
+ children: item.title
2357
+ }), item.label && /* @__PURE__ */ jsx("p", {
2358
+ className: "text-xs text-muted-foreground mt-0.5",
2359
+ children: item.label
2360
+ })]
2361
+ }), item.timestamp && /* @__PURE__ */ jsx("time", {
2362
+ className: "text-xs text-muted-foreground whitespace-nowrap shrink-0",
2363
+ children: item.timestamp
2364
+ })]
2365
+ }),
2366
+ item.description && /* @__PURE__ */ jsx("div", {
2367
+ className: "text-sm text-muted-foreground mt-1",
2368
+ children: item.description
2369
+ }),
2370
+ item.content && /* @__PURE__ */ jsx("div", {
2371
+ className: "mt-2",
2372
+ children: item.content
2373
+ })
2374
+ ]
2375
+ })]
2376
+ });
2377
+ }
2378
+ function HorizontalTimelineItem({ item, isLast, showConnector, size }) {
2379
+ const config = STATUS_CONFIG[item.status || "default"];
2380
+ const sizeConfig = SIZE_CONFIG[size];
2381
+ const renderIcon = () => {
2382
+ if (React$1.isValidElement(item.icon)) return item.icon;
2383
+ return /* @__PURE__ */ jsx(item.icon || config.defaultIcon, { className: sizeConfig.icon });
2384
+ };
2385
+ return /* @__PURE__ */ jsxs("div", {
2386
+ className: "flex flex-col items-center min-w-[120px]",
2387
+ children: [/* @__PURE__ */ jsxs("div", {
2388
+ className: "flex items-center w-full",
2389
+ children: [
2390
+ /* @__PURE__ */ jsx("div", { className: cn("h-0.5 flex-1", showConnector ? config.lineClass : "bg-transparent") }),
2391
+ /* @__PURE__ */ jsx("div", {
2392
+ className: cn("flex items-center justify-center rounded-full shrink-0 mx-1", sizeConfig.dot, config.dotClass),
2393
+ children: renderIcon()
2394
+ }),
2395
+ /* @__PURE__ */ jsx("div", { className: cn("h-0.5 flex-1", showConnector && !isLast ? config.lineClass : "bg-transparent") })
2396
+ ]
2397
+ }), /* @__PURE__ */ jsxs("div", {
2398
+ className: "text-center mt-2 px-2",
2399
+ children: [
2400
+ /* @__PURE__ */ jsx("p", {
2401
+ className: cn("font-medium leading-tight", sizeConfig.text),
2402
+ children: item.title
2403
+ }),
2404
+ item.timestamp && /* @__PURE__ */ jsx("time", {
2405
+ className: "text-xs text-muted-foreground",
2406
+ children: item.timestamp
2407
+ }),
2408
+ item.description && /* @__PURE__ */ jsx("div", {
2409
+ className: "text-xs text-muted-foreground mt-1",
2410
+ children: item.description
2411
+ })
2412
+ ]
2413
+ })]
2414
+ });
2415
+ }
2416
+
2417
+ //#endregion
2418
+ //#region src/components/detail-view.tsx
2419
+ const COLUMN_CLASSES = {
2420
+ 1: "grid-cols-1",
2421
+ 2: "grid-cols-1 sm:grid-cols-2",
2422
+ 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
2423
+ };
2424
+ const SIZE_LABEL = {
2425
+ sm: "text-xs",
2426
+ default: "text-sm",
2427
+ lg: "text-sm"
2428
+ };
2429
+ const SIZE_VALUE = {
2430
+ sm: "text-sm",
2431
+ default: "text-sm",
2432
+ lg: "text-base"
2433
+ };
2434
+ function DetailView({ items, columns = 1, layout = "stacked", size = "default", dividers = false, striped = false, bordered = false, title, description, className, children }) {
2435
+ const visibleItems = items?.filter((item) => !item.hidden) || [];
2436
+ return /* @__PURE__ */ jsxs("div", {
2437
+ className: cn(bordered && "border rounded-lg overflow-hidden", className),
2438
+ children: [(title || description) && /* @__PURE__ */ jsxs("div", {
2439
+ className: cn("space-y-1", bordered ? "px-4 py-3 border-b bg-muted/30" : "mb-4"),
2440
+ children: [title && /* @__PURE__ */ jsx("h3", {
2441
+ className: "text-base font-semibold",
2442
+ children: title
2443
+ }), description && /* @__PURE__ */ jsx("p", {
2444
+ className: "text-sm text-muted-foreground",
2445
+ children: description
2446
+ })]
2447
+ }), children ? /* @__PURE__ */ jsx("div", {
2448
+ className: cn("grid", COLUMN_CLASSES[columns], bordered && "p-4"),
2449
+ children
2450
+ }) : layout === "horizontal" ? /* @__PURE__ */ jsx(HorizontalLayout, {
2451
+ items: visibleItems,
2452
+ size,
2453
+ dividers,
2454
+ striped,
2455
+ bordered
2456
+ }) : layout === "inline" ? /* @__PURE__ */ jsx(InlineLayout, {
2457
+ items: visibleItems,
2458
+ columns,
2459
+ size,
2460
+ bordered
2461
+ }) : /* @__PURE__ */ jsx(StackedLayout, {
2462
+ items: visibleItems,
2463
+ columns,
2464
+ size,
2465
+ dividers,
2466
+ bordered
2467
+ })]
2468
+ });
2469
+ }
2470
+ function StackedLayout({ items, columns, size, dividers, bordered }) {
2471
+ return /* @__PURE__ */ jsx("div", {
2472
+ className: cn("grid gap-4", COLUMN_CLASSES[columns], bordered && "p-4"),
2473
+ children: items.map((item, index) => /* @__PURE__ */ jsxs("div", {
2474
+ className: cn("space-y-1", item.fullWidth && columns > 1 && "col-span-full", dividers && index > 0 && "pt-4 border-t"),
2475
+ children: [/* @__PURE__ */ jsx("dt", {
2476
+ className: cn("text-muted-foreground font-medium", SIZE_LABEL[size]),
2477
+ children: item.label
2478
+ }), /* @__PURE__ */ jsx("dd", {
2479
+ className: cn("text-foreground", SIZE_VALUE[size], item.className),
2480
+ children: item.render ? item.render() : item.value ?? /* @__PURE__ */ jsx("span", {
2481
+ className: "text-muted-foreground/50",
2482
+ children: "-"
2483
+ })
2484
+ })]
2485
+ }, index))
2486
+ });
2487
+ }
2488
+ function HorizontalLayout({ items, size, dividers, striped, bordered }) {
2489
+ return /* @__PURE__ */ jsx("dl", {
2490
+ className: cn(bordered && "divide-y"),
2491
+ children: items.map((item, index) => /* @__PURE__ */ jsxs("div", {
2492
+ className: cn("flex items-start gap-4 py-3", bordered && "px-4", striped && index % 2 === 0 && "bg-muted/30", dividers && !bordered && index > 0 && "border-t"),
2493
+ children: [/* @__PURE__ */ jsx("dt", {
2494
+ className: cn("text-muted-foreground font-medium w-1/3 shrink-0", SIZE_LABEL[size]),
2495
+ children: item.label
2496
+ }), /* @__PURE__ */ jsx("dd", {
2497
+ className: cn("text-foreground flex-1 min-w-0", SIZE_VALUE[size], item.className),
2498
+ children: item.render ? item.render() : item.value ?? /* @__PURE__ */ jsx("span", {
2499
+ className: "text-muted-foreground/50",
2500
+ children: "-"
2501
+ })
2502
+ })]
2503
+ }, index))
2504
+ });
2505
+ }
2506
+ function InlineLayout({ items, columns, size, bordered }) {
2507
+ return /* @__PURE__ */ jsx("div", {
2508
+ className: cn("grid gap-x-6 gap-y-2", COLUMN_CLASSES[columns], bordered && "p-4"),
2509
+ children: items.map((item, index) => /* @__PURE__ */ jsxs("div", {
2510
+ className: cn("flex items-center justify-between gap-2 py-1", item.fullWidth && columns > 1 && "col-span-full"),
2511
+ children: [/* @__PURE__ */ jsx("span", {
2512
+ className: cn("text-muted-foreground", SIZE_LABEL[size]),
2513
+ children: item.label
2514
+ }), /* @__PURE__ */ jsx("span", {
2515
+ className: cn("text-foreground font-medium text-right", SIZE_VALUE[size], item.className),
2516
+ children: item.render ? item.render() : item.value ?? "-"
2517
+ })]
2518
+ }, index))
2519
+ });
2520
+ }
2521
+ function DetailItem({ label, children, value, className, labelClassName, layout = "stacked" }) {
2522
+ const content = children ?? value ?? /* @__PURE__ */ jsx("span", {
2523
+ className: "text-muted-foreground/50",
2524
+ children: "-"
2525
+ });
2526
+ if (layout === "horizontal") return /* @__PURE__ */ jsxs("div", {
2527
+ className: cn("flex items-start gap-4 py-3", className),
2528
+ children: [/* @__PURE__ */ jsx("dt", {
2529
+ className: cn("text-sm text-muted-foreground font-medium w-1/3 shrink-0", labelClassName),
2530
+ children: label
2531
+ }), /* @__PURE__ */ jsx("dd", {
2532
+ className: "text-sm text-foreground flex-1 min-w-0",
2533
+ children: content
2534
+ })]
2535
+ });
2536
+ if (layout === "inline") return /* @__PURE__ */ jsxs("div", {
2537
+ className: cn("flex items-center justify-between gap-2 py-1", className),
2538
+ children: [/* @__PURE__ */ jsx("span", {
2539
+ className: cn("text-sm text-muted-foreground", labelClassName),
2540
+ children: label
2541
+ }), /* @__PURE__ */ jsx("span", {
2542
+ className: "text-sm text-foreground font-medium text-right",
2543
+ children: content
2544
+ })]
2545
+ });
2546
+ return /* @__PURE__ */ jsxs("div", {
2547
+ className: cn("space-y-1", className),
2548
+ children: [/* @__PURE__ */ jsx("dt", {
2549
+ className: cn("text-sm text-muted-foreground font-medium", labelClassName),
2550
+ children: label
2551
+ }), /* @__PURE__ */ jsx("dd", {
2552
+ className: "text-sm text-foreground",
2553
+ children: content
2554
+ })]
2555
+ });
2556
+ }
2557
+
2558
+ //#endregion
2559
+ //#region src/components/animated-wrapper.tsx
2560
+ /** Tailwind utility class for each animation — presence in dist ensures @keyframes emission via @source */
2561
+ const ANIMATION_CLASSES = {
2562
+ fadeIn: "animate-fade-in",
2563
+ fadeInUp: "animate-fade-in-up",
2564
+ scaleIn: "animate-scale-in",
2565
+ slideInLeft: "animate-slide-in-left",
2566
+ slideInRight: "animate-slide-in-right",
2567
+ slideInUp: "animate-slide-in-up",
2568
+ slideInDown: "animate-slide-in-down"
2569
+ };
2570
+ const SLIDE_MAP = {
2571
+ left: "slideInLeft",
2572
+ right: "slideInRight",
2573
+ up: "slideInUp",
2574
+ down: "slideInDown"
2575
+ };
2576
+ /**
2577
+ * useInView — observe when an element enters the viewport.
2578
+ *
2579
+ * @example
2580
+ * ```tsx
2581
+ * const ref = useRef<HTMLDivElement>(null);
2582
+ * const isInView = useInView(ref, { once: true, margin: "-100px" });
2583
+ * return <div ref={ref}>{isInView ? "Visible!" : "Hidden"}</div>;
2584
+ * ```
2585
+ */
2586
+ function useInView(ref, options = {}) {
2587
+ const { margin = "0px", once = true, enabled = true } = options;
2588
+ const [inView, setInView] = useState(false);
2589
+ useEffect(() => {
2590
+ if (!enabled) return;
2591
+ const el = ref.current;
2592
+ if (!el) return;
2593
+ const observer = new IntersectionObserver(([entry]) => {
2594
+ if (entry.isIntersecting) {
2595
+ setInView(true);
2596
+ if (once) observer.unobserve(el);
2597
+ } else if (!once) setInView(false);
2598
+ }, { rootMargin: margin });
2599
+ observer.observe(el);
2600
+ return () => observer.disconnect();
2601
+ }, [
2602
+ enabled,
2603
+ margin,
2604
+ once
2605
+ ]);
2606
+ return inView;
2607
+ }
2608
+ function useAnimationState(opts) {
2609
+ const ref = useRef(null);
2610
+ const shouldAnimate = !opts.disabled;
2611
+ const isInView = useInView(ref, {
2612
+ margin: opts.inViewMargin,
2613
+ once: opts.once,
2614
+ enabled: !!opts.inView && shouldAnimate
2615
+ });
2616
+ return {
2617
+ ref,
2618
+ shouldAnimate,
2619
+ active: shouldAnimate && (!opts.inView || isInView)
2620
+ };
2621
+ }
2622
+ /** Per-instance timing overrides — only emitted when different from theme defaults */
2623
+ function animTimingStyle(delay, duration) {
2624
+ if (delay === 0 && duration === 600) return void 0;
2625
+ return {
2626
+ ...duration !== 600 ? { animationDuration: `${duration}ms` } : {},
2627
+ ...delay > 0 ? { animationDelay: `${delay}ms` } : {}
2628
+ };
2629
+ }
2630
+ function AnimateBase({ animation, children, delay = 0, duration = 600, inView = false, inViewMargin, once = true, disabled = false, className, as = "div" }) {
2631
+ const { ref, shouldAnimate, active } = useAnimationState({
2632
+ inView,
2633
+ inViewMargin,
2634
+ once,
2635
+ disabled
2636
+ });
2637
+ return createElement(as, {
2638
+ ref,
2639
+ "data-fluid-animate": shouldAnimate ? "" : void 0,
2640
+ className: cn(shouldAnimate && "opacity-0", active && ANIMATION_CLASSES[animation], className),
2641
+ style: active ? animTimingStyle(delay, duration) : void 0
2642
+ }, children);
2643
+ }
2644
+ /** Fade in with opacity transition */
2645
+ function FadeIn(props) {
2646
+ return /* @__PURE__ */ jsx(AnimateBase, {
2647
+ animation: "fadeIn",
2648
+ ...props
2649
+ });
2650
+ }
2651
+ /** Fade in with upward motion */
2652
+ function FadeInUp(props) {
2653
+ return /* @__PURE__ */ jsx(AnimateBase, {
2654
+ animation: "fadeInUp",
2655
+ ...props
2656
+ });
2657
+ }
2658
+ /** Scale up into view */
2659
+ function ScaleIn(props) {
2660
+ return /* @__PURE__ */ jsx(AnimateBase, {
2661
+ animation: "scaleIn",
2662
+ ...props
2663
+ });
2664
+ }
2665
+ /** Slide in from a specified direction */
2666
+ function SlideIn({ direction = "left", ...props }) {
2667
+ return /* @__PURE__ */ jsx(AnimateBase, {
2668
+ animation: SLIDE_MAP[direction],
2669
+ ...props
2670
+ });
2671
+ }
2672
+ function StaggerChildren({ children, animation = "fadeInUp", staggerDelay = 100, initialDelay = 0, duration = 600, inView = false, inViewMargin, once = true, disabled = false, className, childClassName, as = "div" }) {
2673
+ const { ref, shouldAnimate, active } = useAnimationState({
2674
+ inView,
2675
+ inViewMargin,
2676
+ once,
2677
+ disabled
2678
+ });
2679
+ const items = Children.toArray(children);
2680
+ return createElement(as, {
2681
+ ref,
2682
+ className
2683
+ }, items.map((child, i) => /* @__PURE__ */ jsx("div", {
2684
+ "data-fluid-animate": shouldAnimate ? "" : void 0,
2685
+ className: cn(shouldAnimate && "opacity-0", active && ANIMATION_CLASSES[animation], childClassName),
2686
+ style: active ? animTimingStyle(initialDelay + i * staggerDelay, duration) : void 0,
2687
+ children: child
2688
+ }, i)));
2689
+ }
2690
+ function AnimatedText({ text, as = "div", animation = "fadeInUp", splitBy = "word", staggerDelay = 80, delay = 0, duration = 600, inView = false, inViewMargin, once = true, disabled = false, className, segmentClassName }) {
2691
+ const { ref, shouldAnimate, active } = useAnimationState({
2692
+ inView,
2693
+ inViewMargin,
2694
+ once,
2695
+ disabled
2696
+ });
2697
+ const segments = splitBy === "word" ? text.split(" ") : text.split("");
2698
+ let animIndex = 0;
2699
+ return createElement(as, {
2700
+ ref,
2701
+ className
2702
+ }, segments.map((segment, i) => {
2703
+ if (splitBy === "character" && segment === " ") return /* @__PURE__ */ jsx(Fragment$1, { children: "\xA0" }, i);
2704
+ const idx = animIndex++;
2705
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [splitBy === "word" && i > 0 && " ", /* @__PURE__ */ jsx("span", {
2706
+ "data-fluid-animate": shouldAnimate ? "" : void 0,
2707
+ className: cn("inline-block", shouldAnimate && "opacity-0", active && ANIMATION_CLASSES[animation], segmentClassName),
2708
+ style: active ? animTimingStyle(delay + idx * staggerDelay, duration) : void 0,
2709
+ children: segment
2710
+ })] }, i);
2711
+ }));
2712
+ }
2713
+ function easeOutCubic(t) {
2714
+ return 1 - Math.pow(1 - t, 3);
2715
+ }
2716
+ function AnimatedCounter({ from = 0, to, duration = 2e3, delay = 0, locale, prefix, suffix, decimals = 0, formatter, inView = false, inViewMargin, once = true, disabled = false, className, as = "span" }) {
2717
+ const ref = useRef(null);
2718
+ const isInView = useInView(ref, {
2719
+ margin: inViewMargin,
2720
+ once,
2721
+ enabled: inView && !disabled
2722
+ });
2723
+ const active = !disabled && (!inView || isInView);
2724
+ const [count, setCount] = useState(from);
2725
+ const hasStarted = useRef(false);
2726
+ useEffect(() => {
2727
+ if (disabled) {
2728
+ setCount(to);
2729
+ return;
2730
+ }
2731
+ if (!active || hasStarted.current) return;
2732
+ hasStarted.current = true;
2733
+ if (typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
2734
+ setCount(to);
2735
+ return;
2736
+ }
2737
+ const timeout = setTimeout(() => {
2738
+ const start = performance.now();
2739
+ const step = (now) => {
2740
+ const elapsed = now - start;
2741
+ const progress = Math.min(elapsed / duration, 1);
2742
+ const eased = easeOutCubic(progress);
2743
+ const current = from + (to - from) * eased;
2744
+ setCount(decimals > 0 ? Number(current.toFixed(decimals)) : Math.round(current));
2745
+ if (progress < 1) requestAnimationFrame(step);
2746
+ };
2747
+ requestAnimationFrame(step);
2748
+ }, delay);
2749
+ return () => clearTimeout(timeout);
2750
+ }, [
2751
+ active,
2752
+ disabled,
2753
+ from,
2754
+ to,
2755
+ duration,
2756
+ delay,
2757
+ decimals
2758
+ ]);
2759
+ const formatValue = (v) => {
2760
+ if (formatter) return formatter(v);
2761
+ if (locale) return v.toLocaleString(locale, {
2762
+ minimumFractionDigits: decimals,
2763
+ maximumFractionDigits: decimals
2764
+ });
2765
+ if (decimals > 0) return v.toFixed(decimals);
2766
+ return String(v);
2767
+ };
2768
+ return createElement(as, {
2769
+ ref,
2770
+ className
2771
+ }, /* @__PURE__ */ jsxs(Fragment, { children: [
2772
+ prefix,
2773
+ formatValue(count),
2774
+ suffix
2775
+ ] }));
2776
+ }
2777
+
2778
+ //#endregion
2779
+ export { AccordionSection, ActionDropdown, ActionTooltip, AnimatedCounter, AnimatedText, ApiPagination, ButtonTooltip, CardWrapper, CheckboxDropdown, ClientSubmitButton, CollapsibleCard, CollapsibleSection, CollapsibleWrapper, ConfirmDialog, ConfirmSheet, CopyButton, CopyCodeBlock, CopyText, CustomPagination, DEFAULT_COUNTRIES, DataCard, DeleteConfirmDialog, DetailItem, DetailView, DialogWrapper, DraggableCard, DropdownWrapper, DynamicTabs, ErrorState, ErrorStateInline, FadeIn, FadeInUp, FaqAccordion, FeatureItem, FeatureList, FormDialog, FormSheet, IconItemMedia, IconTooltip, InfoAlert, InfoRow, InfoTooltip, LoadingCard, PaginationInfo, PhoneInput, Pill, PillAvatar, PillAvatarGroup, PillButton, PillDelta, PillIcon, PillIndicator, PillStatus, RadioDropdown, ResponsiveSplitLayout, ScaleIn, SelectDropdown, SheetWrapper, SimpleTable, SlideIn, StaggerChildren, StatsCard, StatusBanner, StepContent, Stepper, TabContent, TabTrigger, TableWrapper, TabsWrapper, Thumbnail, Timeline, TooltipWrapper, useInView };