@classytic/fluid 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +21 -1
  2. package/dist/client/calendar.d.mts +1 -2
  3. package/dist/client/calendar.mjs +4 -4
  4. package/dist/client/color-picker.d.mts +41 -25
  5. package/dist/client/color-picker.mjs +121 -73
  6. package/dist/client/core.d.mts +243 -557
  7. package/dist/client/core.mjs +351 -1462
  8. package/dist/client/error.d.mts +41 -41
  9. package/dist/client/error.mjs +35 -35
  10. package/dist/client/gallery.d.mts +33 -33
  11. package/dist/client/gallery.mjs +128 -127
  12. package/dist/client/hooks.d.mts +57 -39
  13. package/dist/client/hooks.mjs +29 -7
  14. package/dist/client/spreadsheet.d.mts +28 -28
  15. package/dist/client/spreadsheet.mjs +77 -77
  16. package/dist/client/table.d.mts +66 -33
  17. package/dist/client/table.mjs +87 -54
  18. package/dist/client/theme.mjs +1 -1
  19. package/dist/command.d.mts +6 -4
  20. package/dist/command.mjs +3 -3
  21. package/dist/compact.d.mts +97 -95
  22. package/dist/compact.mjs +336 -322
  23. package/dist/dashboard.d.mts +614 -422
  24. package/dist/dashboard.mjs +1051 -762
  25. package/dist/{dropdown-wrapper-B86u9Fri.mjs → dropdown-wrapper-B9nRDUlz.mjs} +25 -35
  26. package/dist/forms.d.mts +1037 -972
  27. package/dist/forms.mjs +2849 -2721
  28. package/dist/index.d.mts +218 -152
  29. package/dist/index.mjs +357 -264
  30. package/dist/layouts.d.mts +94 -94
  31. package/dist/layouts.mjs +115 -110
  32. package/dist/phone-input-B9_XPNvv.mjs +429 -0
  33. package/dist/phone-input-CLH_UjQZ.d.mts +31 -0
  34. package/dist/{search-context-DR7DBs7S.mjs → search-context-1g3ZmOvx.mjs} +1 -1
  35. package/dist/search.d.mts +168 -164
  36. package/dist/search.mjs +305 -301
  37. package/dist/{sheet-wrapper-C13Y-Q6w.mjs → sheet-wrapper-B2uxookb.mjs} +1 -1
  38. package/dist/timeline-Bgu1mIe9.d.mts +373 -0
  39. package/dist/timeline-HJtWf4Op.mjs +804 -0
  40. package/dist/{use-base-search-BGgWnWaF.d.mts → use-base-search-DFC4QKYU.d.mts} +1 -1
  41. package/dist/{use-media-query-BnVNIKT4.mjs → use-media-query-ChLfFChU.mjs} +6 -7
  42. package/package.json +2 -2
  43. /package/dist/{api-pagination-CJ0vR_w6.d.mts → api-pagination-C30ser2L.d.mts} +0 -0
  44. /package/dist/{filter-utils-DqMmy_v-.mjs → filter-utils-BGIvtq1R.mjs} +0 -0
  45. /package/dist/{filter-utils-IZ0GtuPo.d.mts → filter-utils-DOFTBWm1.d.mts} +0 -0
  46. /package/dist/{use-debounce-xmZucz5e.mjs → use-debounce-BNoNiEon.mjs} +0 -0
  47. /package/dist/{use-keyboard-shortcut-Bl6YM5Q7.mjs → use-keyboard-shortcut-C_Vk-36P.mjs} +0 -0
  48. /package/dist/{use-keyboard-shortcut-_mRCh3QO.d.mts → use-keyboard-shortcut-Q4CSPzSI.d.mts} +0 -0
  49. /package/dist/{use-mobile-BX3SQVo2.mjs → use-mobile-CnEmFiQx.mjs} +0 -0
  50. /package/dist/{use-scroll-detection-CsgsQYvy.mjs → use-scroll-detection-BKfqkmEC.mjs} +0 -0
  51. /package/dist/{utils-CDue7cEt.d.mts → utils-rqvYP1by.d.mts} +0 -0
@@ -1,403 +1,317 @@
1
1
  "use client";
2
2
 
3
3
  import { t as cn } from "../utils-DQ5SCVoW.mjs";
4
- import { t as useMediaQuery } from "../use-media-query-BnVNIKT4.mjs";
5
- import { a as SelectDropdown, c as PaginationInfo, i as RadioDropdown, n as CheckboxDropdown, o as ApiPagination, r as DropdownWrapper, s as CustomPagination, t as ActionDropdown } from "../dropdown-wrapper-B86u9Fri.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";
4
+ import { S as FaqAccordion, _ as DataCard, a as PillButton, b as StatsCard, c as PillIndicator, d as CopyButton, f as CopyCodeBlock, g as CardWrapper, h as DetailView, i as PillAvatarGroup, l as PillStatus, m as DetailItem, n as Pill, o as PillDelta, p as CopyText, r as PillAvatar, s as PillIcon, t as Timeline, u as InfoRow, v as DraggableCard, x as AccordionSection, y as LoadingCard } from "../timeline-HJtWf4Op.mjs";
5
+ import { t as useMediaQuery } from "../use-media-query-ChLfFChU.mjs";
6
+ import { a as SelectDropdown, c as PaginationInfo, i as RadioDropdown, n as CheckboxDropdown, o as ApiPagination, r as DropdownWrapper, s as CustomPagination, t as ActionDropdown } from "../dropdown-wrapper-B9nRDUlz.mjs";
7
+ import { i as ClientSubmitButton, n as FormSheet, r as SheetWrapper, t as ConfirmSheet } from "../sheet-wrapper-B2uxookb.mjs";
8
+ import { n as PhoneInput, t as DEFAULT_COUNTRIES } from "../phone-input-B9_XPNvv.mjs";
9
9
  import * as React$1 from "react";
10
- import { Children, Fragment as Fragment$1, createContext, createElement, isValidElement, memo, use, useEffect, useMemo, useRef, useState } from "react";
11
- import { AlertCircle, AlertTriangle, ArrowLeft, ArrowRight, Check, CheckCircle2, ChevronDown, ChevronDownIcon, ChevronUp, ChevronUpIcon, Circle, Copy, Info, Loader2, MinusIcon, 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";
10
+ import { Children, Fragment, createContext, createElement, isValidElement, memo, use, useEffect, useMemo, useRef, useState } from "react";
11
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
+ import { AlertCircle, AlertTriangle, ArrowLeft, ArrowRight, Check, CheckCircle2, ChevronDown, ChevronUp, Info, Loader2, RefreshCw, X } from "lucide-react";
14
13
  import { Button } from "@/components/ui/button";
14
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
15
15
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
16
16
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
17
17
  import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
18
18
  import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
19
19
  import { cva } from "class-variance-authority";
20
20
  import { Item, ItemContent, ItemDescription } from "@/components/ui/item";
21
- import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
22
- import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/ui/input-group";
23
- import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
24
21
  import { ScrollArea } from "@/components/ui/scroll-area";
25
- import { Badge } from "@/components/ui/badge";
26
- import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
27
22
  import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
28
23
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
29
24
  import Image from "next/image";
30
25
  import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
31
26
 
32
- //#region src/components/accordion-wrapper.tsx
33
- /**
34
- * AccordionSection - Single collapsible section with smooth animation
35
- *
36
- * @example
37
- * ```tsx
38
- * <AccordionSection title="Settings" icon={<Settings className="h-4 w-4" />}>
39
- * <div>Content here</div>
40
- * </AccordionSection>
41
- * ```
42
- */
43
- const AccordionSection = memo(function AccordionSection({ title, icon, children, defaultOpen = false, className, badge }) {
44
- return /* @__PURE__ */ jsx(Accordion, {
45
- defaultValue: defaultOpen ? ["section"] : [],
46
- className,
47
- children: /* @__PURE__ */ jsxs(AccordionItem, {
48
- value: "section",
49
- className: "border-0",
50
- children: [/* @__PURE__ */ jsx(AccordionTrigger, {
51
- className: "py-3 hover:no-underline",
52
- children: /* @__PURE__ */ jsxs("div", {
53
- className: "flex items-center gap-2",
54
- children: [
55
- icon && /* @__PURE__ */ jsx("span", {
56
- className: "text-muted-foreground",
57
- children: icon
58
- }),
59
- /* @__PURE__ */ jsx("span", {
60
- className: "font-medium",
61
- children: title
62
- }),
63
- badge
64
- ]
65
- })
66
- }), /* @__PURE__ */ jsx(AccordionContent, { children: /* @__PURE__ */ jsx("div", {
67
- className: "pt-2",
68
- children
69
- }) })]
70
- })
71
- });
72
- });
27
+ //#region src/components/animated-wrapper.tsx
28
+ /** Tailwind utility class for each animation — presence in dist ensures @keyframes emission via @source */
29
+ const ANIMATION_CLASSES = {
30
+ fadeIn: "animate-fade-in",
31
+ fadeInUp: "animate-fade-in-up",
32
+ scaleIn: "animate-scale-in",
33
+ slideInLeft: "animate-slide-in-left",
34
+ slideInRight: "animate-slide-in-right",
35
+ slideInUp: "animate-slide-in-up",
36
+ slideInDown: "animate-slide-in-down"
37
+ };
38
+ const SLIDE_MAP = {
39
+ left: "slideInLeft",
40
+ right: "slideInRight",
41
+ up: "slideInUp",
42
+ down: "slideInDown"
43
+ };
73
44
  /**
74
- * FaqAccordion - FAQ-style accordion where only one item can be open by default
45
+ * useInView observe when an element enters the viewport.
75
46
  *
76
47
  * @example
77
48
  * ```tsx
78
- * <FaqAccordion
79
- * items={[
80
- * { id: "1", question: "What is this?", answer: "A FAQ accordion" },
81
- * { id: "2", question: "How does it work?", answer: "Click to expand" },
82
- * ]}
83
- * />
49
+ * const ref = useRef<HTMLDivElement>(null);
50
+ * const isInView = useInView(ref, { once: true, margin: "-100px" });
51
+ * return <div ref={ref}>{isInView ? "Visible!" : "Hidden"}</div>;
84
52
  * ```
85
53
  */
86
- const FaqAccordion = memo(function FaqAccordion({ items, defaultOpen, className, multiple = false }) {
87
- return /* @__PURE__ */ jsx(Accordion, {
88
- defaultValue: defaultOpen ? [defaultOpen] : [],
89
- multiple,
90
- className: cn("w-full", className),
91
- children: items.map((item) => /* @__PURE__ */ jsxs(AccordionItem, {
92
- value: item.id,
93
- children: [/* @__PURE__ */ jsx(AccordionTrigger, {
94
- className: "text-left",
95
- children: item.question
96
- }), /* @__PURE__ */ jsx(AccordionContent, { children: item.answer })]
97
- }, item.id))
98
- });
99
- });
100
-
101
- //#endregion
102
- //#region src/components/card-wrapper.tsx
103
- const CARD_VARIANTS = {
104
- default: "",
105
- outline: "border-2",
106
- ghost: "border-0 shadow-none bg-transparent",
107
- elevated: "shadow-lg border-0",
108
- primary: "border-primary/20 bg-primary/5",
109
- secondary: "border-secondary/20 bg-secondary/5",
110
- destructive: "border-destructive/20 bg-destructive/5",
111
- success: "border-green-500/20 bg-green-500/5",
112
- warning: "border-yellow-500/20 bg-yellow-500/5"
113
- };
114
- const CARD_SIZES = {
115
- sm: "p-3",
116
- default: "p-6",
117
- lg: "p-8",
118
- xl: "p-10"
119
- };
120
- const CARD_CONTENT_SIZES = {
121
- sm: "pt-3",
122
- default: "pt-6",
123
- lg: "pt-8",
124
- xl: "pt-10"
125
- };
126
- function CardWrapper({ title, description, children, footer, className, headerClassName, contentClassName, footerClassName, variant = "default", size = "default", hideHeader = false, ...props }) {
127
- return /* @__PURE__ */ jsxs(Card, {
128
- className: cn(CARD_VARIANTS[variant], className),
129
- ...props,
130
- children: [
131
- !hideHeader && (title || description) && /* @__PURE__ */ jsxs(CardHeader, {
132
- className: cn(CARD_SIZES[size], "pb-4", headerClassName),
133
- children: [title && /* @__PURE__ */ jsx(CardTitle, {
134
- className: "text-lg font-semibold",
135
- children: title
136
- }), description && /* @__PURE__ */ jsx(CardDescription, { children: description })]
137
- }),
138
- /* @__PURE__ */ jsx(CardContent, {
139
- className: cn(hideHeader ? CARD_SIZES[size] : CARD_CONTENT_SIZES[size], contentClassName),
140
- children
141
- }),
142
- footer && /* @__PURE__ */ jsx(CardFooter, {
143
- className: cn(CARD_SIZES[size], "pt-4 border-t", footerClassName),
144
- children: /* @__PURE__ */ jsx("div", {
145
- className: "w-full",
146
- children: footer
147
- })
148
- })
149
- ]
150
- });
54
+ function useInView(ref, options = {}) {
55
+ const { margin = "0px", once = true, enabled = true } = options;
56
+ const [inView, setInView] = useState(false);
57
+ useEffect(() => {
58
+ if (!enabled) return;
59
+ const el = ref.current;
60
+ if (!el) return;
61
+ const observer = new IntersectionObserver(([entry]) => {
62
+ if (entry.isIntersecting) {
63
+ setInView(true);
64
+ if (once) observer.unobserve(el);
65
+ } else if (!once) setInView(false);
66
+ }, { rootMargin: margin });
67
+ observer.observe(el);
68
+ return () => observer.disconnect();
69
+ }, [
70
+ enabled,
71
+ margin,
72
+ once
73
+ ]);
74
+ return inView;
151
75
  }
152
- const DATA_CARD_COLS = {
153
- 1: "grid-cols-1",
154
- 2: "grid-cols-2",
155
- 3: "grid-cols-2 md:grid-cols-3",
156
- 4: "grid-cols-2 md:grid-cols-4"
157
- };
158
- function DataCard({ title, data, cols = 3, className, ...props }) {
159
- return /* @__PURE__ */ jsx(CardWrapper, {
160
- title,
161
- className: cn("space-y-4", className),
162
- ...props,
163
- children: /* @__PURE__ */ jsx("div", {
164
- className: cn("grid gap-4", DATA_CARD_COLS[cols]),
165
- children: data.map((item, index) => /* @__PURE__ */ jsxs("div", {
166
- className: "space-y-1",
167
- children: [/* @__PURE__ */ jsx("p", {
168
- className: "text-sm text-muted-foreground",
169
- children: item.label
170
- }), /* @__PURE__ */ jsx("p", {
171
- className: cn("text-lg font-semibold", item.color),
172
- children: item.value
173
- })]
174
- }, index))
175
- })
76
+ function useAnimationState(opts) {
77
+ const ref = useRef(null);
78
+ const shouldAnimate = !opts.disabled;
79
+ const isInView = useInView(ref, {
80
+ margin: opts.inViewMargin,
81
+ once: opts.once,
82
+ enabled: !!opts.inView && shouldAnimate
176
83
  });
84
+ return {
85
+ ref,
86
+ shouldAnimate,
87
+ active: shouldAnimate && (!opts.inView || isInView)
88
+ };
177
89
  }
178
- function LoadingCard({ title, description, className, ...props }) {
179
- return /* @__PURE__ */ jsx(CardWrapper, {
180
- title,
181
- description,
182
- className,
183
- ...props,
184
- children: /* @__PURE__ */ jsxs("div", {
185
- className: "flex items-center justify-center py-8",
186
- children: [/* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary" }), /* @__PURE__ */ jsx("span", {
187
- className: "ml-2",
188
- children: "Loading..."
189
- })]
190
- })
191
- });
90
+ /** Per-instance timing overrides only emitted when different from theme defaults */
91
+ function animTimingStyle(delay, duration) {
92
+ if (delay === 0 && duration === 600) return void 0;
93
+ return {
94
+ ...duration !== 600 ? { animationDuration: `${duration}ms` } : {},
95
+ ...delay > 0 ? { animationDelay: `${delay}ms` } : {}
96
+ };
192
97
  }
193
- const STATS_CARD_VARIANTS = {
194
- default: "",
195
- success: "bg-green-50 border-green-200 dark:bg-green-950/30 dark:border-green-900",
196
- warning: "bg-yellow-50 border-yellow-200 dark:bg-yellow-950/30 dark:border-yellow-900",
197
- danger: "bg-red-50 border-red-200 dark:bg-red-950/30 dark:border-red-900",
198
- info: "bg-blue-50 border-blue-200 dark:bg-blue-950/30 dark:border-blue-900"
199
- };
200
- const STATS_ICON_VARIANTS = {
201
- default: "text-muted-foreground",
202
- success: "text-green-600 dark:text-green-400",
203
- warning: "text-yellow-600 dark:text-yellow-400",
204
- danger: "text-red-600 dark:text-red-400",
205
- info: "text-blue-600 dark:text-blue-400"
206
- };
207
- const STATS_ICON_WRAPPER_VARIANTS = {
208
- default: "bg-muted border border-border",
209
- success: "bg-green-100/50 dark:bg-green-900/30",
210
- warning: "bg-yellow-100/50 dark:bg-yellow-900/30",
211
- danger: "bg-red-100/50 dark:bg-red-900/30",
212
- info: "bg-blue-100/50 dark:bg-blue-900/30"
213
- };
214
- function StatsCard({ title, value, description, icon, trend, className, statsVariant = "default", iconClassName, ...props }) {
215
- return /* @__PURE__ */ jsxs(CardWrapper, {
216
- className: cn("relative overflow-hidden", STATS_CARD_VARIANTS[statsVariant], className),
217
- size: "sm",
218
- hideHeader: true,
219
- ...props,
220
- children: [/* @__PURE__ */ jsxs("div", {
221
- className: "flex items-center justify-between",
222
- children: [/* @__PURE__ */ jsxs("div", {
223
- className: "space-y-1",
224
- children: [
225
- /* @__PURE__ */ jsx("p", {
226
- className: "text-sm font-medium text-muted-foreground",
227
- children: title
228
- }),
229
- /* @__PURE__ */ jsx("p", {
230
- className: "text-2xl font-bold",
231
- children: value
232
- }),
233
- description && /* @__PURE__ */ jsx("p", {
234
- className: "text-xs text-muted-foreground",
235
- children: description
236
- })
237
- ]
238
- }), icon && /* @__PURE__ */ jsx("div", {
239
- className: cn("p-2 rounded-md", STATS_ICON_WRAPPER_VARIANTS[statsVariant], STATS_ICON_VARIANTS[statsVariant], iconClassName),
240
- children: icon
241
- })]
242
- }), trend && /* @__PURE__ */ jsx("div", {
243
- 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"),
244
- children: trend.value
245
- })]
98
+ function AnimateBase({ animation, children, delay = 0, duration = 600, inView = false, inViewMargin, once = true, disabled = false, className, as = "div" }) {
99
+ const { ref, shouldAnimate, active } = useAnimationState({
100
+ inView,
101
+ inViewMargin,
102
+ once,
103
+ disabled
246
104
  });
105
+ return createElement(as, {
106
+ ref,
107
+ "data-fluid-animate": shouldAnimate ? "" : void 0,
108
+ className: cn(shouldAnimate && "opacity-0", active && ANIMATION_CLASSES[animation], className),
109
+ style: active ? animTimingStyle(delay, duration) : void 0
110
+ }, children);
247
111
  }
248
- function DraggableCard({ title, subtitle, badges, actions, details, dragHandleProps, className, isDragging, isHidden, children, ...props }) {
249
- return /* @__PURE__ */ jsx(CardWrapper, {
250
- hideHeader: true,
251
- className: cn("transition-all", isDragging && "shadow-lg rotate-2", isHidden && "opacity-50", className),
252
- contentClassName: "!pt-4",
253
- ...props,
254
- children: /* @__PURE__ */ jsxs("div", {
255
- className: "flex items-start gap-3",
256
- children: [
257
- dragHandleProps && /* @__PURE__ */ jsx("div", {
258
- ...dragHandleProps,
259
- className: "mt-1 cursor-grab hover:text-foreground",
260
- children: dragHandleProps.icon || /* @__PURE__ */ jsxs("svg", {
261
- xmlns: "http://www.w3.org/2000/svg",
262
- width: "16",
263
- height: "16",
264
- viewBox: "0 0 24 24",
265
- fill: "none",
266
- stroke: "currentColor",
267
- strokeWidth: "2",
268
- strokeLinecap: "round",
269
- strokeLinejoin: "round",
270
- className: "text-muted-foreground",
271
- children: [
272
- /* @__PURE__ */ jsx("circle", {
273
- cx: "9",
274
- cy: "12",
275
- r: "1"
276
- }),
277
- /* @__PURE__ */ jsx("circle", {
278
- cx: "9",
279
- cy: "5",
280
- r: "1"
281
- }),
282
- /* @__PURE__ */ jsx("circle", {
283
- cx: "9",
284
- cy: "19",
285
- r: "1"
286
- }),
287
- /* @__PURE__ */ jsx("circle", {
288
- cx: "15",
289
- cy: "12",
290
- r: "1"
291
- }),
292
- /* @__PURE__ */ jsx("circle", {
293
- cx: "15",
294
- cy: "5",
295
- r: "1"
296
- }),
297
- /* @__PURE__ */ jsx("circle", {
298
- cx: "15",
299
- cy: "19",
300
- r: "1"
301
- })
302
- ]
303
- })
304
- }),
305
- /* @__PURE__ */ jsxs("div", {
306
- className: "flex-1 min-w-0 space-y-3",
307
- children: [
308
- /* @__PURE__ */ jsxs("div", {
309
- className: "flex flex-wrap items-center gap-2",
310
- children: [title && /* @__PURE__ */ jsx("h4", {
311
- className: "font-medium",
312
- children: title
313
- }), badges && /* @__PURE__ */ jsx("div", {
314
- className: "flex flex-wrap gap-1",
315
- children: badges
316
- })]
317
- }),
318
- subtitle && /* @__PURE__ */ jsx("p", {
319
- className: "text-xs text-muted-foreground break-words",
320
- children: subtitle
321
- }),
322
- details,
323
- children
324
- ]
325
- }),
326
- actions && /* @__PURE__ */ jsx("div", {
327
- className: "flex items-center gap-2 flex-shrink-0",
328
- children: actions
329
- })
330
- ]
331
- })
112
+ /** Fade in with opacity transition */
113
+ function FadeIn(props) {
114
+ return /* @__PURE__ */ jsx(AnimateBase, {
115
+ animation: "fadeIn",
116
+ ...props
332
117
  });
333
118
  }
334
-
335
- //#endregion
336
- //#region src/components/collapsible-wrapper.tsx
337
- function CollapsibleWrapper({ children, trigger, defaultOpen = false, open, onOpenChange, triggerAsChild = false, triggerVariant = "outline", triggerSize = "sm", triggerClassName, contentClassName, className, showChevron = true, chevronPosition = "right", disabled = false, ...props }) {
338
- const [internalOpen, setInternalOpen] = useState(defaultOpen);
339
- const isOpen = open !== void 0 ? open : internalOpen;
340
- const handleOpenChange = onOpenChange || setInternalOpen;
341
- const chevronElement = showChevron && /* @__PURE__ */ jsx("div", {
342
- className: cn("flex items-center", chevronPosition === "left" && "order-first mr-2", chevronPosition === "right" && "ml-2"),
343
- children: isOpen ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
119
+ /** Fade in with upward motion */
120
+ function FadeInUp(props) {
121
+ return /* @__PURE__ */ jsx(AnimateBase, {
122
+ animation: "fadeInUp",
123
+ ...props
344
124
  });
345
- return /* @__PURE__ */ jsxs(Collapsible, {
346
- open: isOpen,
347
- onOpenChange: handleOpenChange,
348
- disabled,
349
- className: cn("w-full", className),
350
- ...props,
351
- children: [triggerAsChild && isValidElement(trigger) ? /* @__PURE__ */ jsx(CollapsibleTrigger, { render: trigger }) : /* @__PURE__ */ jsxs(CollapsibleTrigger, {
352
- render: /* @__PURE__ */ jsx(Button, {
353
- variant: triggerVariant,
354
- size: triggerSize,
355
- disabled,
356
- className: cn("justify-between", triggerClassName)
357
- }),
358
- children: [trigger, chevronElement]
359
- }), /* @__PURE__ */ jsx(CollapsibleContent, {
360
- className: cn("mt-2", contentClassName),
361
- children
362
- })]
125
+ }
126
+ /** Scale up into view */
127
+ function ScaleIn(props) {
128
+ return /* @__PURE__ */ jsx(AnimateBase, {
129
+ animation: "scaleIn",
130
+ ...props
363
131
  });
364
132
  }
365
- function CollapsibleCard({ title, children, defaultOpen = false, className, headerClassName, contentClassName, ...props }) {
366
- const [isOpen, setIsOpen] = useState(defaultOpen);
367
- return /* @__PURE__ */ jsxs(Collapsible, {
368
- open: isOpen,
369
- onOpenChange: setIsOpen,
370
- className: cn("border rounded-lg overflow-hidden", className),
371
- ...props,
372
- children: [/* @__PURE__ */ jsxs(CollapsibleTrigger, {
373
- render: /* @__PURE__ */ jsx("button", {
374
- type: "button",
375
- 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)
376
- }),
377
- children: [/* @__PURE__ */ jsx("span", {
378
- className: "font-medium",
379
- children: title
380
- }), /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200", isOpen && "rotate-180") })]
381
- }), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", {
382
- className: cn("px-4 py-3 border-t", contentClassName),
383
- children
384
- }) })]
133
+ /** Slide in from a specified direction */
134
+ function SlideIn({ direction = "left", ...props }) {
135
+ return /* @__PURE__ */ jsx(AnimateBase, {
136
+ animation: SLIDE_MAP[direction],
137
+ ...props
385
138
  });
386
139
  }
387
- function CollapsibleSection({ label, children, defaultOpen = false, className, labelClassName, contentClassName, ...props }) {
388
- return /* @__PURE__ */ jsx(CollapsibleWrapper, {
389
- trigger: label,
390
- defaultOpen,
391
- triggerVariant: "ghost",
392
- triggerSize: "sm",
393
- triggerClassName: cn("h-8 px-2 font-medium justify-between", labelClassName),
394
- contentClassName: cn("pl-4 mt-1", contentClassName),
395
- className: cn("space-y-1", className),
396
- ...props,
397
- children
140
+ function StaggerChildren({ children, animation = "fadeInUp", staggerDelay = 100, initialDelay = 0, duration = 600, inView = false, inViewMargin, once = true, disabled = false, className, childClassName, as = "div" }) {
141
+ const { ref, shouldAnimate, active } = useAnimationState({
142
+ inView,
143
+ inViewMargin,
144
+ once,
145
+ disabled
398
146
  });
147
+ const items = Children.toArray(children);
148
+ return createElement(as, {
149
+ ref,
150
+ className
151
+ }, items.map((child, i) => /* @__PURE__ */ jsx("div", {
152
+ "data-fluid-animate": shouldAnimate ? "" : void 0,
153
+ className: cn(shouldAnimate && "opacity-0", active && ANIMATION_CLASSES[animation], childClassName),
154
+ style: active ? animTimingStyle(initialDelay + i * staggerDelay, duration) : void 0,
155
+ children: child
156
+ }, i)));
399
157
  }
400
-
158
+ function AnimatedText({ text, as = "div", animation = "fadeInUp", splitBy = "word", staggerDelay = 80, delay = 0, duration = 600, inView = false, inViewMargin, once = true, disabled = false, className, segmentClassName }) {
159
+ const { ref, shouldAnimate, active } = useAnimationState({
160
+ inView,
161
+ inViewMargin,
162
+ once,
163
+ disabled
164
+ });
165
+ const segments = splitBy === "word" ? text.split(" ") : text.split("");
166
+ let animIndex = 0;
167
+ return createElement(as, {
168
+ ref,
169
+ className
170
+ }, segments.map((segment, i) => {
171
+ if (splitBy === "character" && segment === " ") return /* @__PURE__ */ jsx(Fragment, { children: "\xA0" }, i);
172
+ const idx = animIndex++;
173
+ return /* @__PURE__ */ jsxs(Fragment, { children: [splitBy === "word" && i > 0 && " ", /* @__PURE__ */ jsx("span", {
174
+ "data-fluid-animate": shouldAnimate ? "" : void 0,
175
+ className: cn("inline-block", shouldAnimate && "opacity-0", active && ANIMATION_CLASSES[animation], segmentClassName),
176
+ style: active ? animTimingStyle(delay + idx * staggerDelay, duration) : void 0,
177
+ children: segment
178
+ })] }, i);
179
+ }));
180
+ }
181
+ function easeOutCubic(t) {
182
+ return 1 - (1 - t) ** 3;
183
+ }
184
+ 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" }) {
185
+ const ref = useRef(null);
186
+ const isInView = useInView(ref, {
187
+ margin: inViewMargin,
188
+ once,
189
+ enabled: inView && !disabled
190
+ });
191
+ const active = !disabled && (!inView || isInView);
192
+ const [count, setCount] = useState(from);
193
+ const hasStarted = useRef(false);
194
+ useEffect(() => {
195
+ if (disabled) {
196
+ setCount(to);
197
+ return;
198
+ }
199
+ if (!active || hasStarted.current) return;
200
+ hasStarted.current = true;
201
+ if (typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
202
+ setCount(to);
203
+ return;
204
+ }
205
+ const timeout = setTimeout(() => {
206
+ const start = performance.now();
207
+ const step = (now) => {
208
+ const elapsed = now - start;
209
+ const progress = Math.min(elapsed / duration, 1);
210
+ const eased = easeOutCubic(progress);
211
+ const current = from + (to - from) * eased;
212
+ setCount(decimals > 0 ? Number(current.toFixed(decimals)) : Math.round(current));
213
+ if (progress < 1) requestAnimationFrame(step);
214
+ };
215
+ requestAnimationFrame(step);
216
+ }, delay);
217
+ return () => clearTimeout(timeout);
218
+ }, [
219
+ active,
220
+ disabled,
221
+ from,
222
+ to,
223
+ duration,
224
+ delay,
225
+ decimals
226
+ ]);
227
+ const formatValue = (v) => {
228
+ if (formatter) return formatter(v);
229
+ if (locale) return v.toLocaleString(locale, {
230
+ minimumFractionDigits: decimals,
231
+ maximumFractionDigits: decimals
232
+ });
233
+ if (decimals > 0) return v.toFixed(decimals);
234
+ return String(v);
235
+ };
236
+ return createElement(as, {
237
+ ref,
238
+ className,
239
+ "aria-live": "polite",
240
+ "aria-atomic": "true"
241
+ }, /* @__PURE__ */ jsxs(Fragment$1, { children: [
242
+ prefix,
243
+ formatValue(count),
244
+ suffix
245
+ ] }));
246
+ }
247
+
248
+ //#endregion
249
+ //#region src/components/collapsible-wrapper.tsx
250
+ function CollapsibleWrapper({ children, trigger, defaultOpen = false, open, onOpenChange, triggerAsChild = false, triggerVariant = "outline", triggerSize = "sm", triggerClassName, contentClassName, className, showChevron = true, chevronPosition = "right", disabled = false, ...props }) {
251
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
252
+ const isOpen = open !== void 0 ? open : internalOpen;
253
+ const handleOpenChange = onOpenChange || setInternalOpen;
254
+ const chevronElement = showChevron && /* @__PURE__ */ jsx("div", {
255
+ className: cn("flex items-center", chevronPosition === "left" && "order-first mr-2", chevronPosition === "right" && "ml-2"),
256
+ children: isOpen ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
257
+ });
258
+ return /* @__PURE__ */ jsxs(Collapsible, {
259
+ open: isOpen,
260
+ onOpenChange: handleOpenChange,
261
+ disabled,
262
+ className: cn("w-full", className),
263
+ ...props,
264
+ children: [triggerAsChild && isValidElement(trigger) ? /* @__PURE__ */ jsx(CollapsibleTrigger, { render: trigger }) : /* @__PURE__ */ jsxs(CollapsibleTrigger, {
265
+ render: /* @__PURE__ */ jsx(Button, {
266
+ variant: triggerVariant,
267
+ size: triggerSize,
268
+ disabled,
269
+ className: cn("justify-between", triggerClassName)
270
+ }),
271
+ children: [trigger, chevronElement]
272
+ }), /* @__PURE__ */ jsx(CollapsibleContent, {
273
+ className: cn("mt-2", contentClassName),
274
+ children
275
+ })]
276
+ });
277
+ }
278
+ function CollapsibleCard({ title, children, defaultOpen = false, className, headerClassName, contentClassName, ...props }) {
279
+ const [isOpen, setIsOpen] = useState(defaultOpen);
280
+ return /* @__PURE__ */ jsxs(Collapsible, {
281
+ open: isOpen,
282
+ onOpenChange: setIsOpen,
283
+ className: cn("border rounded-lg overflow-hidden", className),
284
+ ...props,
285
+ children: [/* @__PURE__ */ jsxs(CollapsibleTrigger, {
286
+ render: /* @__PURE__ */ jsx("button", {
287
+ type: "button",
288
+ "aria-expanded": isOpen,
289
+ 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)
290
+ }),
291
+ children: [/* @__PURE__ */ jsx("span", {
292
+ className: "font-medium",
293
+ children: title
294
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200", isOpen && "rotate-180") })]
295
+ }), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", {
296
+ className: cn("px-4 py-3 border-t", contentClassName),
297
+ children
298
+ }) })]
299
+ });
300
+ }
301
+ function CollapsibleSection({ label, children, defaultOpen = false, className, labelClassName, contentClassName, ...props }) {
302
+ return /* @__PURE__ */ jsx(CollapsibleWrapper, {
303
+ trigger: label,
304
+ defaultOpen,
305
+ triggerVariant: "ghost",
306
+ triggerSize: "sm",
307
+ triggerClassName: cn("h-8 px-2 font-medium justify-between", labelClassName),
308
+ contentClassName: cn("pl-4 mt-1", contentClassName),
309
+ className: cn("space-y-1", className),
310
+ ...props,
311
+ children
312
+ });
313
+ }
314
+
401
315
  //#endregion
402
316
  //#region src/components/confirm-dialog.tsx
403
317
  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 }) {
@@ -408,16 +322,11 @@ function ConfirmDialog({ open, onOpenChange, trigger, title = "Are you sure?", d
408
322
  if (onCancel) onCancel();
409
323
  else onOpenChange(false);
410
324
  };
411
- const triggerChildren = (trigger?.props)?.children;
412
- const triggerElement = trigger ? React$1.cloneElement(trigger, { children: void 0 }) : null;
413
325
  return /* @__PURE__ */ jsxs(AlertDialog, {
414
326
  open,
415
327
  onOpenChange,
416
328
  ...props,
417
- children: [triggerElement && /* @__PURE__ */ jsx(AlertDialogTrigger, {
418
- render: triggerElement,
419
- children: triggerChildren
420
- }), /* @__PURE__ */ jsxs(AlertDialogContent, {
329
+ children: [trigger && /* @__PURE__ */ jsx(AlertDialogTrigger, { render: trigger }), /* @__PURE__ */ jsxs(AlertDialogContent, {
421
330
  className: cn("max-w-md", className),
422
331
  children: [
423
332
  /* @__PURE__ */ jsxs(AlertDialogHeader, {
@@ -503,75 +412,6 @@ function InfoAlert({ title, description, confirmText = "OK", onConfirm, onOpenCh
503
412
  });
504
413
  }
505
414
 
506
- //#endregion
507
- //#region src/components/copy-button.tsx
508
- async function copyToClipboard(text, options) {
509
- try {
510
- await navigator.clipboard.writeText(text);
511
- return true;
512
- } catch {
513
- return false;
514
- }
515
- }
516
- function CopyButton({ value, className, size = "sm", variant = "ghost", showToast = true, toastMessage = "Copied to clipboard", errorMessage = "Failed to copy to clipboard", timeout = 2e3, children, ...props }) {
517
- const [copied, setCopied] = useState(false);
518
- const handleCopy = async () => {
519
- if (!value) return;
520
- if (await copyToClipboard(value, {
521
- showToast,
522
- successMessage: toastMessage,
523
- errorMessage
524
- })) {
525
- setCopied(true);
526
- setTimeout(() => setCopied(false), timeout);
527
- }
528
- };
529
- return /* @__PURE__ */ jsx(Button, {
530
- variant,
531
- size,
532
- className: cn("h-6 w-6 p-0", className),
533
- onClick: handleCopy,
534
- disabled: !value,
535
- ...props,
536
- children: children || (copied ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 text-green-600" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3" }))
537
- });
538
- }
539
- function CopyText({ value, displayValue, className, textClassName, buttonClassName, maxLength = 30, showButton = true, ...buttonProps }) {
540
- const truncatedValue = displayValue || (value && value.length > maxLength ? `${value.substring(0, maxLength)}...` : value || "N/A");
541
- return /* @__PURE__ */ jsxs("div", {
542
- className: cn("flex items-center gap-2", className),
543
- children: [/* @__PURE__ */ jsx("span", {
544
- className: cn("font-medium", textClassName),
545
- title: value || "N/A",
546
- children: truncatedValue
547
- }), showButton && value && /* @__PURE__ */ jsx(CopyButton, {
548
- value,
549
- className: buttonClassName,
550
- ...buttonProps
551
- })]
552
- });
553
- }
554
- function CopyCodeBlock({ value, className, language, showLineNumbers = false, ...buttonProps }) {
555
- return /* @__PURE__ */ jsxs("div", {
556
- className: cn("relative group", className),
557
- children: [/* @__PURE__ */ jsx("pre", {
558
- className: "bg-muted p-4 rounded-md overflow-x-auto text-sm",
559
- children: /* @__PURE__ */ jsx("code", {
560
- className: language ? `language-${language}` : "",
561
- children: value
562
- })
563
- }), /* @__PURE__ */ jsx("div", {
564
- className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity",
565
- children: /* @__PURE__ */ jsx(CopyButton, {
566
- value,
567
- variant: "secondary",
568
- size: "sm",
569
- ...buttonProps
570
- })
571
- })]
572
- });
573
- }
574
-
575
415
  //#endregion
576
416
  //#region src/components/dialog-wrapper.tsx
577
417
  const SIZE_VARIANTS = {
@@ -680,6 +520,7 @@ function ErrorStateInline({ error, onRetry, className, icon }) {
680
520
  const errorMessage = typeof error === "string" ? error : error?.message || "Error loading data";
681
521
  return /* @__PURE__ */ jsxs("div", {
682
522
  className: cn("flex items-center gap-2 text-sm text-destructive", className),
523
+ role: "alert",
683
524
  children: [
684
525
  icon || /* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4" }),
685
526
  /* @__PURE__ */ jsx("span", { children: errorMessage }),
@@ -694,34 +535,6 @@ function ErrorStateInline({ error, onRetry, className, icon }) {
694
535
  });
695
536
  }
696
537
 
697
- //#endregion
698
- //#region src/components/info-row.tsx
699
- function InfoRow({ label, value, copyable = false, icon: Icon }) {
700
- if (!value && value !== 0) return null;
701
- return /* @__PURE__ */ jsxs("div", {
702
- 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",
703
- children: [/* @__PURE__ */ jsxs("div", {
704
- className: "flex items-center gap-2 min-w-0",
705
- children: [Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 text-muted-foreground flex-shrink-0" }), /* @__PURE__ */ jsx("span", {
706
- className: "text-sm font-medium text-muted-foreground truncate",
707
- children: label
708
- })]
709
- }), /* @__PURE__ */ jsx("div", {
710
- className: "sm:text-right min-w-0 flex-shrink-0",
711
- children: copyable ? /* @__PURE__ */ jsx(CopyText, {
712
- value: String(value),
713
- textClassName: "text-foreground font-semibold",
714
- maxLength: 40,
715
- className: "justify-start sm:justify-end"
716
- }) : /* @__PURE__ */ jsx("span", {
717
- className: "font-semibold text-foreground block truncate max-w-full sm:max-w-[250px]",
718
- title: value?.toString() || "N/A",
719
- children: value?.toString() || "N/A"
720
- })
721
- })]
722
- });
723
- }
724
-
725
538
  //#endregion
726
539
  //#region src/components/item-helpers.tsx
727
540
  /**
@@ -839,479 +652,40 @@ function FeatureList({ items = [], columns = 3, variant = "outline", iconBg = "p
839
652
  FeatureList.displayName = "FeatureList";
840
653
 
841
654
  //#endregion
842
- //#region src/components/phone-input.tsx
843
- const DEFAULT_COUNTRIES = [
844
- {
845
- code: "GB",
846
- name: "United Kingdom",
847
- dialCode: "+44",
848
- flag: "🇬🇧"
849
- },
850
- {
851
- code: "US",
852
- name: "United States",
853
- dialCode: "+1",
854
- flag: "🇺🇸"
855
- },
856
- {
857
- code: "IE",
858
- name: "Ireland",
859
- dialCode: "+353",
860
- flag: "🇮🇪"
861
- },
862
- {
863
- code: "FR",
864
- name: "France",
865
- dialCode: "+33",
866
- flag: "🇫🇷"
867
- },
868
- {
869
- code: "DE",
870
- name: "Germany",
871
- dialCode: "+49",
872
- flag: "🇩🇪"
873
- },
874
- {
875
- code: "IT",
876
- name: "Italy",
877
- dialCode: "+39",
878
- flag: "🇮🇹"
879
- },
880
- {
881
- code: "ES",
882
- name: "Spain",
883
- dialCode: "+34",
884
- flag: "🇪🇸"
885
- },
886
- {
887
- code: "NL",
888
- name: "Netherlands",
889
- dialCode: "+31",
890
- flag: "🇳🇱"
891
- },
892
- {
893
- code: "BE",
894
- name: "Belgium",
895
- dialCode: "+32",
896
- flag: "🇧🇪"
897
- },
898
- {
899
- code: "PT",
900
- name: "Portugal",
901
- dialCode: "+351",
902
- flag: "🇵🇹"
903
- },
904
- {
905
- code: "CH",
906
- name: "Switzerland",
907
- dialCode: "+41",
908
- flag: "🇨🇭"
909
- },
910
- {
911
- code: "AT",
912
- name: "Austria",
913
- dialCode: "+43",
914
- flag: "🇦🇹"
915
- },
916
- {
917
- code: "SE",
918
- name: "Sweden",
919
- dialCode: "+46",
920
- flag: "🇸🇪"
921
- },
922
- {
923
- code: "NO",
924
- name: "Norway",
925
- dialCode: "+47",
926
- flag: "🇳🇴"
927
- },
928
- {
929
- code: "DK",
930
- name: "Denmark",
931
- dialCode: "+45",
932
- flag: "🇩🇰"
933
- },
934
- {
935
- code: "PL",
936
- name: "Poland",
937
- dialCode: "+48",
938
- flag: "🇵🇱"
939
- },
940
- {
941
- code: "GR",
942
- name: "Greece",
943
- dialCode: "+30",
944
- flag: "🇬🇷"
945
- },
946
- {
947
- code: "CZ",
948
- name: "Czech Republic",
949
- dialCode: "+420",
950
- flag: "🇨🇿"
951
- },
952
- {
953
- code: "RO",
954
- name: "Romania",
955
- dialCode: "+40",
956
- flag: "🇷🇴"
957
- },
958
- {
959
- code: "HU",
960
- name: "Hungary",
961
- dialCode: "+36",
962
- flag: "🇭🇺"
963
- },
964
- {
965
- code: "AU",
966
- name: "Australia",
967
- dialCode: "+61",
968
- flag: "🇦🇺"
969
- },
970
- {
971
- code: "NZ",
972
- name: "New Zealand",
973
- dialCode: "+64",
974
- flag: "🇳🇿"
975
- },
976
- {
977
- code: "CA",
978
- name: "Canada",
979
- dialCode: "+1",
980
- flag: "🇨🇦"
981
- },
982
- {
983
- code: "IN",
984
- name: "India",
985
- dialCode: "+91",
986
- flag: "🇮🇳"
987
- },
988
- {
989
- code: "PK",
990
- name: "Pakistan",
991
- dialCode: "+92",
992
- flag: "🇵🇰"
993
- },
994
- {
995
- code: "BD",
996
- name: "Bangladesh",
997
- dialCode: "+880",
998
- flag: "🇧🇩"
999
- },
1000
- {
1001
- code: "AE",
1002
- name: "UAE",
1003
- dialCode: "+971",
1004
- flag: "🇦🇪"
1005
- },
1006
- {
1007
- code: "SA",
1008
- name: "Saudi Arabia",
1009
- dialCode: "+966",
1010
- flag: "🇸🇦"
1011
- },
1012
- {
1013
- code: "QA",
1014
- name: "Qatar",
1015
- dialCode: "+974",
1016
- flag: "🇶🇦"
1017
- },
1018
- {
1019
- code: "KW",
1020
- name: "Kuwait",
1021
- dialCode: "+965",
1022
- flag: "🇰🇼"
1023
- },
1024
- {
1025
- code: "SG",
1026
- name: "Singapore",
1027
- dialCode: "+65",
1028
- flag: "🇸🇬"
1029
- },
1030
- {
1031
- code: "MY",
1032
- name: "Malaysia",
1033
- dialCode: "+60",
1034
- flag: "🇲🇾"
1035
- },
1036
- {
1037
- code: "JP",
1038
- name: "Japan",
1039
- dialCode: "+81",
1040
- flag: "🇯🇵"
1041
- },
1042
- {
1043
- code: "KR",
1044
- name: "South Korea",
1045
- dialCode: "+82",
1046
- flag: "🇰🇷"
1047
- },
1048
- {
1049
- code: "CN",
1050
- name: "China",
1051
- dialCode: "+86",
1052
- flag: "🇨🇳"
1053
- },
1054
- {
1055
- code: "HK",
1056
- name: "Hong Kong",
1057
- dialCode: "+852",
1058
- flag: "🇭🇰"
1059
- },
1060
- {
1061
- code: "TW",
1062
- name: "Taiwan",
1063
- dialCode: "+886",
1064
- flag: "🇹🇼"
1065
- },
1066
- {
1067
- code: "TH",
1068
- name: "Thailand",
1069
- dialCode: "+66",
1070
- flag: "🇹🇭"
1071
- },
1072
- {
1073
- code: "PH",
1074
- name: "Philippines",
1075
- dialCode: "+63",
1076
- flag: "🇵🇭"
1077
- },
1078
- {
1079
- code: "VN",
1080
- name: "Vietnam",
1081
- dialCode: "+84",
1082
- flag: "🇻🇳"
1083
- },
1084
- {
1085
- code: "ID",
1086
- name: "Indonesia",
1087
- dialCode: "+62",
1088
- flag: "🇮🇩"
1089
- },
1090
- {
1091
- code: "ZA",
1092
- name: "South Africa",
1093
- dialCode: "+27",
1094
- flag: "🇿🇦"
1095
- },
1096
- {
1097
- code: "NG",
1098
- name: "Nigeria",
1099
- dialCode: "+234",
1100
- flag: "🇳🇬"
1101
- },
1102
- {
1103
- code: "EG",
1104
- name: "Egypt",
1105
- dialCode: "+20",
1106
- flag: "🇪🇬"
1107
- },
1108
- {
1109
- code: "BR",
1110
- name: "Brazil",
1111
- dialCode: "+55",
1112
- flag: "🇧🇷"
1113
- },
1114
- {
1115
- code: "MX",
1116
- name: "Mexico",
1117
- dialCode: "+52",
1118
- flag: "🇲🇽"
1119
- },
1120
- {
1121
- code: "AR",
1122
- name: "Argentina",
1123
- dialCode: "+54",
1124
- flag: "🇦🇷"
1125
- },
1126
- {
1127
- code: "TR",
1128
- name: "Turkey",
1129
- dialCode: "+90",
1130
- flag: "🇹🇷"
1131
- },
1132
- {
1133
- code: "RU",
1134
- name: "Russia",
1135
- dialCode: "+7",
1136
- flag: "🇷🇺"
1137
- },
1138
- {
1139
- code: "IL",
1140
- name: "Israel",
1141
- dialCode: "+972",
1142
- flag: "🇮🇱"
655
+ //#region src/components/printable-view.tsx
656
+ function PrintableView({ children, id, className }) {
657
+ return /* @__PURE__ */ jsx("div", {
658
+ id,
659
+ className: cn("hidden print:block", className),
660
+ children
661
+ });
662
+ }
663
+ function printDocument(elementId, options = {}) {
664
+ const { title = "Print", styles = "", copyStyles = true } = options;
665
+ const element = document.getElementById(elementId);
666
+ if (!element) {
667
+ console.warn(`printDocument: element with id "${elementId}" not found`);
668
+ return;
1143
669
  }
1144
- ];
1145
- function PhoneInput({ className, onChange, value, defaultCountry = "GB", countries = DEFAULT_COUNTRIES, disabled, placeholder = "Phone number", ref, ...props }) {
1146
- const [isOpen, setIsOpen] = React$1.useState(false);
1147
- const [searchValue, setSearchValue] = React$1.useState("");
1148
- const getCountryByCode = React$1.useCallback((code) => countries.find((c) => c.code === code), [countries]);
1149
- const parseValue = React$1.useCallback((val) => {
1150
- const valString = val ? String(val) : "";
1151
- if (!valString) return {
1152
- country: getCountryByCode(defaultCountry) || countries[0],
1153
- number: ""
1154
- };
1155
- const cleanVal = valString.replace(/\s/g, "");
1156
- for (const country of countries) if (cleanVal.startsWith(country.dialCode)) return {
1157
- country,
1158
- number: cleanVal.slice(country.dialCode.length)
1159
- };
1160
- return {
1161
- country: getCountryByCode(defaultCountry) || countries[0],
1162
- number: cleanVal.replace(/^\+/, "")
1163
- };
1164
- }, [
1165
- defaultCountry,
1166
- countries,
1167
- getCountryByCode
1168
- ]);
1169
- const { country, number } = parseValue(value);
1170
- const [selectedCountry, setSelectedCountry] = React$1.useState(country);
1171
- React$1.useEffect(() => {
1172
- setSelectedCountry(parseValue(value).country);
1173
- }, [value, parseValue]);
1174
- const handleCountryChange = (newCountry) => {
1175
- setSelectedCountry(newCountry);
1176
- setIsOpen(false);
1177
- if (number) onChange?.(newCountry.dialCode + number);
1178
- };
1179
- const handleNumberChange = (e) => {
1180
- const newNumber = e.target.value.replace(/[^\d]/g, "");
1181
- if (newNumber) onChange?.(selectedCountry.dialCode + newNumber);
1182
- else onChange?.("");
670
+ const printWindow = window.open("", "_blank", "width=800,height=600");
671
+ if (!printWindow) {
672
+ window.print();
673
+ return;
674
+ }
675
+ printWindow.document.write(`<!DOCTYPE html><html><head><title>${title}</title>`);
676
+ if (copyStyles) document.querySelectorAll("link[rel=\"stylesheet\"], style").forEach((node) => {
677
+ printWindow.document.write(node.outerHTML);
678
+ });
679
+ if (styles) printWindow.document.write(`<style>${styles}</style>`);
680
+ printWindow.document.write("</head><body>");
681
+ printWindow.document.write(element.innerHTML);
682
+ printWindow.document.write("</body></html>");
683
+ printWindow.document.close();
684
+ printWindow.onload = () => {
685
+ printWindow.focus();
686
+ printWindow.print();
687
+ printWindow.close();
1183
688
  };
1184
- return /* @__PURE__ */ jsxs(InputGroup, {
1185
- className,
1186
- children: [/* @__PURE__ */ jsx(InputGroupAddon, {
1187
- align: "inline-start",
1188
- className: "p-0 overflow-hidden",
1189
- children: /* @__PURE__ */ jsxs(Popover, {
1190
- open: isOpen,
1191
- modal: true,
1192
- onOpenChange: (open) => {
1193
- setIsOpen(open);
1194
- if (open) setSearchValue("");
1195
- },
1196
- children: [/* @__PURE__ */ jsx(PopoverTrigger, { render: /* @__PURE__ */ jsxs(Button, {
1197
- type: "button",
1198
- variant: "ghost",
1199
- className: "gap-1.5 rounded-none border-r px-3 focus:z-10 min-w-[90px] h-full",
1200
- disabled,
1201
- children: [
1202
- /* @__PURE__ */ jsx("span", {
1203
- className: "text-base leading-none",
1204
- children: selectedCountry.flag
1205
- }),
1206
- /* @__PURE__ */ jsx("span", {
1207
- className: "text-xs text-muted-foreground",
1208
- children: selectedCountry.dialCode
1209
- }),
1210
- /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 opacity-50" })
1211
- ]
1212
- }) }), /* @__PURE__ */ jsx(PopoverContent, {
1213
- className: "w-[280px] p-0",
1214
- align: "start",
1215
- children: /* @__PURE__ */ jsxs(Command, { children: [/* @__PURE__ */ jsx(CommandInput, {
1216
- value: searchValue,
1217
- onValueChange: setSearchValue,
1218
- placeholder: "Search country..."
1219
- }), /* @__PURE__ */ jsx(CommandList, { children: /* @__PURE__ */ jsxs(ScrollArea, {
1220
- className: "h-64",
1221
- 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, {
1222
- className: "gap-2 cursor-pointer",
1223
- onSelect: () => handleCountryChange(c),
1224
- value: `${c.name} ${c.code} ${c.dialCode}`,
1225
- children: [
1226
- /* @__PURE__ */ jsx("span", {
1227
- className: "text-base",
1228
- children: c.flag
1229
- }),
1230
- /* @__PURE__ */ jsx("span", {
1231
- className: "flex-1 text-sm",
1232
- children: c.name
1233
- }),
1234
- /* @__PURE__ */ jsx("span", {
1235
- className: "text-sm text-muted-foreground",
1236
- children: c.dialCode
1237
- })
1238
- ]
1239
- }, c.code)) })]
1240
- }) })] })
1241
- })]
1242
- })
1243
- }), /* @__PURE__ */ jsx(InputGroupInput, {
1244
- ref,
1245
- type: "tel",
1246
- inputMode: "numeric",
1247
- className: "rounded-s-none",
1248
- placeholder,
1249
- value: number,
1250
- onChange: handleNumberChange,
1251
- disabled,
1252
- ...props
1253
- })]
1254
- });
1255
- }
1256
-
1257
- //#endregion
1258
- //#region src/components/pill.tsx
1259
- function Pill({ variant = "secondary", themed = false, className, ...props }) {
1260
- return /* @__PURE__ */ jsx(Badge, {
1261
- className: cn("gap-2 rounded-full px-3 py-1.5 font-normal", className),
1262
- variant,
1263
- ...props
1264
- });
1265
- }
1266
- function PillAvatar({ fallback, className, src, alt, ...props }) {
1267
- return /* @__PURE__ */ jsxs(Avatar, {
1268
- className: cn("-ml-1 h-4 w-4", className),
1269
- children: [/* @__PURE__ */ jsx(AvatarImage, {
1270
- src,
1271
- alt,
1272
- ...props
1273
- }), /* @__PURE__ */ jsx(AvatarFallback, { children: fallback })]
1274
- });
1275
- }
1276
- function PillButton({ className, ...props }) {
1277
- return /* @__PURE__ */ jsx(Button, {
1278
- className: cn("-my-2 -mr-2 size-6 rounded-full p-0.5 hover:bg-foreground/5", className),
1279
- size: "icon",
1280
- variant: "ghost",
1281
- ...props
1282
- });
1283
- }
1284
- function PillStatus({ children, className, ...props }) {
1285
- return /* @__PURE__ */ jsx("div", {
1286
- className: cn("flex items-center gap-2 border-r pr-2 font-medium", className),
1287
- ...props,
1288
- children
1289
- });
1290
- }
1291
- function PillIndicator({ variant = "success", pulse = false }) {
1292
- return /* @__PURE__ */ jsxs("span", {
1293
- className: "relative flex size-2",
1294
- 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") })]
1295
- });
1296
- }
1297
- function PillDelta({ className, delta }) {
1298
- if (!delta) return /* @__PURE__ */ jsx(MinusIcon, { className: cn("size-3 text-muted-foreground", className) });
1299
- if (delta > 0) return /* @__PURE__ */ jsx(ChevronUpIcon, { className: cn("size-3 text-emerald-500", className) });
1300
- return /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("size-3 text-rose-500", className) });
1301
- }
1302
- function PillIcon({ icon: Icon, className, ...props }) {
1303
- return /* @__PURE__ */ jsx(Icon, {
1304
- className: cn("size-3 text-muted-foreground", className),
1305
- size: 12,
1306
- ...props
1307
- });
1308
- }
1309
- function PillAvatarGroup({ children, className, ...props }) {
1310
- return /* @__PURE__ */ jsx("div", {
1311
- 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),
1312
- ...props,
1313
- children
1314
- });
1315
689
  }
1316
690
 
1317
691
  //#endregion
@@ -1909,6 +1283,30 @@ function StepContent({ step, currentStep, children, className, keepMounted = fal
1909
1283
  });
1910
1284
  }
1911
1285
 
1286
+ //#endregion
1287
+ //#region src/components/submit-footer.tsx
1288
+ function SubmitFooter({ onCancel, onSubmit, isLoading = false, submitLabel = "Save", cancelLabel = "Cancel", submitVariant = "default", formSubmit = false, disabled = false, leftContent, className }) {
1289
+ return /* @__PURE__ */ jsxs("div", {
1290
+ className: cn("flex items-center gap-2 pt-4", className),
1291
+ children: [leftContent && /* @__PURE__ */ jsxs(Fragment$1, { children: [leftContent, /* @__PURE__ */ jsx("div", { className: "flex-1" })] }), /* @__PURE__ */ jsxs("div", {
1292
+ className: cn("flex items-center gap-2", !leftContent && "ml-auto"),
1293
+ children: [/* @__PURE__ */ jsx(Button, {
1294
+ type: "button",
1295
+ variant: "outline",
1296
+ onClick: onCancel,
1297
+ disabled: isLoading,
1298
+ children: cancelLabel
1299
+ }), /* @__PURE__ */ jsxs(Button, {
1300
+ type: formSubmit ? "submit" : "button",
1301
+ variant: submitVariant,
1302
+ onClick: formSubmit ? void 0 : onSubmit,
1303
+ disabled: disabled || isLoading,
1304
+ children: [isLoading && /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), submitLabel]
1305
+ })]
1306
+ })]
1307
+ });
1308
+ }
1309
+
1912
1310
  //#endregion
1913
1311
  //#region src/components/table-wrapper.tsx
1914
1312
  function TableWrapper({ title, description, icon, children, columns, data, renderRow, emptyState, className, tableClassName, maxHeight = "500px", ...props }) {
@@ -1992,6 +1390,16 @@ function Thumbnail({ src, alt, aspect = "square", size = "medium", className, fa
1992
1390
  return /* @__PURE__ */ jsx("div", {
1993
1391
  className: cn("relative rounded-md overflow-hidden", aspectRatios[aspect], sizeClass, onClick && "cursor-pointer", className),
1994
1392
  onClick,
1393
+ ...onClick ? {
1394
+ role: "button",
1395
+ tabIndex: 0,
1396
+ onKeyDown: (e) => {
1397
+ if (e.key === "Enter" || e.key === " ") {
1398
+ e.preventDefault();
1399
+ onClick();
1400
+ }
1401
+ }
1402
+ } : {},
1995
1403
  children: /* @__PURE__ */ jsx(Image, {
1996
1404
  src: src || fallback,
1997
1405
  alt: alt || "Thumbnail",
@@ -2014,7 +1422,7 @@ const getSizes = (size) => {
2014
1422
  //#endregion
2015
1423
  //#region src/components/tooltip-wrapper.tsx
2016
1424
  function TooltipWrapper({ children, content, side = "top", align = "center", delay = 700, sideOffset = 4, className, contentClassName, disabled = false, ...props }) {
2017
- if (disabled || !content) return /* @__PURE__ */ jsx(Fragment, { children });
1425
+ if (disabled || !content) return /* @__PURE__ */ jsx(Fragment$1, { children });
2018
1426
  return /* @__PURE__ */ jsxs(Tooltip, {
2019
1427
  delay,
2020
1428
  ...props,
@@ -2056,13 +1464,15 @@ function InfoTooltip({ tooltip, className, size = 16, ...props }) {
2056
1464
  content: tooltip,
2057
1465
  className: cn("inline-flex items-center", className),
2058
1466
  ...props,
2059
- children: /* @__PURE__ */ jsx("div", {
2060
- className: "rounded-full bg-muted text-muted-foreground hover:bg-muted/80 transition-colors cursor-help inline-flex items-center justify-center",
1467
+ children: /* @__PURE__ */ jsx("button", {
1468
+ type: "button",
1469
+ className: "rounded-full bg-muted text-muted-foreground hover:bg-muted/80 transition-colors cursor-help inline-flex items-center justify-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
2061
1470
  style: {
2062
1471
  width: size,
2063
1472
  height: size,
2064
1473
  fontSize: size * .6
2065
1474
  },
1475
+ "aria-label": "More information",
2066
1476
  children: "?"
2067
1477
  })
2068
1478
  });
@@ -2072,6 +1482,7 @@ function ActionTooltip({ children, tooltip, action, variant = "ghost", size = "s
2072
1482
  content: tooltip,
2073
1483
  ...props,
2074
1484
  children: /* @__PURE__ */ jsx("button", {
1485
+ type: "button",
2075
1486
  onClick: action,
2076
1487
  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),
2077
1488
  children
@@ -2080,526 +1491,4 @@ function ActionTooltip({ children, tooltip, action, variant = "ghost", size = "s
2080
1491
  }
2081
1492
 
2082
1493
  //#endregion
2083
- //#region src/components/timeline.tsx
2084
- const STATUS_CONFIG = {
2085
- default: {
2086
- dotClass: "bg-muted-foreground/20 text-muted-foreground",
2087
- lineClass: "bg-border",
2088
- defaultIcon: Circle
2089
- },
2090
- success: {
2091
- dotClass: "bg-green-500/20 text-green-600 dark:text-green-400",
2092
- lineClass: "bg-green-500/30",
2093
- defaultIcon: Check
2094
- },
2095
- error: {
2096
- dotClass: "bg-red-500/20 text-red-600 dark:text-red-400",
2097
- lineClass: "bg-red-500/30",
2098
- defaultIcon: X
2099
- },
2100
- warning: {
2101
- dotClass: "bg-yellow-500/20 text-yellow-600 dark:text-yellow-400",
2102
- lineClass: "bg-yellow-500/30",
2103
- defaultIcon: AlertTriangle
2104
- },
2105
- pending: {
2106
- dotClass: "bg-muted text-muted-foreground animate-pulse",
2107
- lineClass: "bg-border border-dashed",
2108
- defaultIcon: Circle
2109
- },
2110
- active: {
2111
- dotClass: "bg-primary/20 text-primary ring-2 ring-primary/30",
2112
- lineClass: "bg-primary/30",
2113
- defaultIcon: Circle
2114
- }
2115
- };
2116
- const SIZE_CONFIG = {
2117
- sm: {
2118
- dot: "h-6 w-6",
2119
- icon: "h-3 w-3",
2120
- gap: "gap-3",
2121
- text: "text-xs"
2122
- },
2123
- default: {
2124
- dot: "h-8 w-8",
2125
- icon: "h-4 w-4",
2126
- gap: "gap-4",
2127
- text: "text-sm"
2128
- },
2129
- lg: {
2130
- dot: "h-10 w-10",
2131
- icon: "h-5 w-5",
2132
- gap: "gap-5",
2133
- text: "text-base"
2134
- }
2135
- };
2136
- function Timeline({ items, orientation = "vertical", size = "default", showConnectors = true, reverse = false, className }) {
2137
- const sizeConfig = SIZE_CONFIG[size];
2138
- const orderedItems = reverse ? [...items].reverse() : items;
2139
- if (orientation === "horizontal") return /* @__PURE__ */ jsx("div", {
2140
- className: cn("flex overflow-x-auto", sizeConfig.gap, className),
2141
- children: orderedItems.map((item, index) => /* @__PURE__ */ jsx(HorizontalTimelineItem, {
2142
- item,
2143
- isLast: index === orderedItems.length - 1,
2144
- showConnector: showConnectors,
2145
- size
2146
- }, index))
2147
- });
2148
- return /* @__PURE__ */ jsx("div", {
2149
- className: cn("relative", className),
2150
- children: orderedItems.map((item, index) => /* @__PURE__ */ jsx(VerticalTimelineItem, {
2151
- item,
2152
- isLast: index === orderedItems.length - 1,
2153
- showConnector: showConnectors,
2154
- size
2155
- }, index))
2156
- });
2157
- }
2158
- function VerticalTimelineItem({ item, isLast, showConnector, size }) {
2159
- const config = STATUS_CONFIG[item.status || "default"];
2160
- const sizeConfig = SIZE_CONFIG[size];
2161
- const renderIcon = () => {
2162
- if (React$1.isValidElement(item.icon)) return item.icon;
2163
- return /* @__PURE__ */ jsx(item.icon || config.defaultIcon, { className: sizeConfig.icon });
2164
- };
2165
- return /* @__PURE__ */ jsxs("div", {
2166
- className: cn("flex", sizeConfig.gap, "pb-6 last:pb-0"),
2167
- children: [/* @__PURE__ */ jsxs("div", {
2168
- className: "flex flex-col items-center shrink-0",
2169
- children: [/* @__PURE__ */ jsx("div", {
2170
- className: cn("flex items-center justify-center rounded-full shrink-0", sizeConfig.dot, config.dotClass),
2171
- children: renderIcon()
2172
- }), showConnector && !isLast && /* @__PURE__ */ jsx("div", { className: cn("w-0.5 flex-1 mt-2", config.lineClass) })]
2173
- }), /* @__PURE__ */ jsxs("div", {
2174
- className: "min-w-0 flex-1 pt-0.5 pb-2",
2175
- children: [
2176
- /* @__PURE__ */ jsxs("div", {
2177
- className: "flex items-start justify-between gap-2",
2178
- children: [/* @__PURE__ */ jsxs("div", {
2179
- className: "min-w-0",
2180
- children: [/* @__PURE__ */ jsx("p", {
2181
- className: cn("font-medium leading-tight", sizeConfig.text),
2182
- children: item.title
2183
- }), item.label && /* @__PURE__ */ jsx("p", {
2184
- className: "text-xs text-muted-foreground mt-0.5",
2185
- children: item.label
2186
- })]
2187
- }), item.timestamp && /* @__PURE__ */ jsx("time", {
2188
- className: "text-xs text-muted-foreground whitespace-nowrap shrink-0",
2189
- children: item.timestamp
2190
- })]
2191
- }),
2192
- item.description && /* @__PURE__ */ jsx("div", {
2193
- className: "text-sm text-muted-foreground mt-1",
2194
- children: item.description
2195
- }),
2196
- item.content && /* @__PURE__ */ jsx("div", {
2197
- className: "mt-2",
2198
- children: item.content
2199
- })
2200
- ]
2201
- })]
2202
- });
2203
- }
2204
- function HorizontalTimelineItem({ item, isLast, showConnector, size }) {
2205
- const config = STATUS_CONFIG[item.status || "default"];
2206
- const sizeConfig = SIZE_CONFIG[size];
2207
- const renderIcon = () => {
2208
- if (React$1.isValidElement(item.icon)) return item.icon;
2209
- return /* @__PURE__ */ jsx(item.icon || config.defaultIcon, { className: sizeConfig.icon });
2210
- };
2211
- return /* @__PURE__ */ jsxs("div", {
2212
- className: "flex flex-col items-center min-w-[120px]",
2213
- children: [/* @__PURE__ */ jsxs("div", {
2214
- className: "flex items-center w-full",
2215
- children: [
2216
- /* @__PURE__ */ jsx("div", { className: cn("h-0.5 flex-1", showConnector ? config.lineClass : "bg-transparent") }),
2217
- /* @__PURE__ */ jsx("div", {
2218
- className: cn("flex items-center justify-center rounded-full shrink-0 mx-1", sizeConfig.dot, config.dotClass),
2219
- children: renderIcon()
2220
- }),
2221
- /* @__PURE__ */ jsx("div", { className: cn("h-0.5 flex-1", showConnector && !isLast ? config.lineClass : "bg-transparent") })
2222
- ]
2223
- }), /* @__PURE__ */ jsxs("div", {
2224
- className: "text-center mt-2 px-2",
2225
- children: [
2226
- /* @__PURE__ */ jsx("p", {
2227
- className: cn("font-medium leading-tight", sizeConfig.text),
2228
- children: item.title
2229
- }),
2230
- item.timestamp && /* @__PURE__ */ jsx("time", {
2231
- className: "text-xs text-muted-foreground",
2232
- children: item.timestamp
2233
- }),
2234
- item.description && /* @__PURE__ */ jsx("div", {
2235
- className: "text-xs text-muted-foreground mt-1",
2236
- children: item.description
2237
- })
2238
- ]
2239
- })]
2240
- });
2241
- }
2242
-
2243
- //#endregion
2244
- //#region src/components/detail-view.tsx
2245
- const COLUMN_CLASSES = {
2246
- 1: "grid-cols-1",
2247
- 2: "grid-cols-1 sm:grid-cols-2",
2248
- 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
2249
- };
2250
- const SIZE_LABEL = {
2251
- sm: "text-xs",
2252
- default: "text-sm",
2253
- lg: "text-sm"
2254
- };
2255
- const SIZE_VALUE = {
2256
- sm: "text-sm",
2257
- default: "text-sm",
2258
- lg: "text-base"
2259
- };
2260
- function DetailView({ items, columns = 1, layout = "stacked", size = "default", dividers = false, striped = false, bordered = false, title, description, className, children }) {
2261
- const visibleItems = items?.filter((item) => !item.hidden) || [];
2262
- return /* @__PURE__ */ jsxs("div", {
2263
- className: cn(bordered && "border rounded-lg overflow-hidden", className),
2264
- children: [(title || description) && /* @__PURE__ */ jsxs("div", {
2265
- className: cn("space-y-1", bordered ? "px-4 py-3 border-b bg-muted/30" : "mb-4"),
2266
- children: [title && /* @__PURE__ */ jsx("h3", {
2267
- className: "text-base font-semibold",
2268
- children: title
2269
- }), description && /* @__PURE__ */ jsx("p", {
2270
- className: "text-sm text-muted-foreground",
2271
- children: description
2272
- })]
2273
- }), children ? /* @__PURE__ */ jsx("div", {
2274
- className: cn("grid", COLUMN_CLASSES[columns], bordered && "p-4"),
2275
- children
2276
- }) : layout === "horizontal" ? /* @__PURE__ */ jsx(HorizontalLayout, {
2277
- items: visibleItems,
2278
- size,
2279
- dividers,
2280
- striped,
2281
- bordered
2282
- }) : layout === "inline" ? /* @__PURE__ */ jsx(InlineLayout, {
2283
- items: visibleItems,
2284
- columns,
2285
- size,
2286
- bordered
2287
- }) : /* @__PURE__ */ jsx(StackedLayout, {
2288
- items: visibleItems,
2289
- columns,
2290
- size,
2291
- dividers,
2292
- bordered
2293
- })]
2294
- });
2295
- }
2296
- function StackedLayout({ items, columns, size, dividers, bordered }) {
2297
- return /* @__PURE__ */ jsx("div", {
2298
- className: cn("grid gap-4", COLUMN_CLASSES[columns], bordered && "p-4"),
2299
- children: items.map((item, index) => /* @__PURE__ */ jsxs("div", {
2300
- className: cn("space-y-1", item.fullWidth && columns > 1 && "col-span-full", dividers && index > 0 && "pt-4 border-t"),
2301
- children: [/* @__PURE__ */ jsx("dt", {
2302
- className: cn("text-muted-foreground font-medium", SIZE_LABEL[size]),
2303
- children: item.label
2304
- }), /* @__PURE__ */ jsx("dd", {
2305
- className: cn("text-foreground", SIZE_VALUE[size], item.className),
2306
- children: item.render ? item.render() : item.value ?? /* @__PURE__ */ jsx("span", {
2307
- className: "text-muted-foreground/50",
2308
- children: "-"
2309
- })
2310
- })]
2311
- }, index))
2312
- });
2313
- }
2314
- function HorizontalLayout({ items, size, dividers, striped, bordered }) {
2315
- return /* @__PURE__ */ jsx("dl", {
2316
- className: cn(bordered && "divide-y"),
2317
- children: items.map((item, index) => /* @__PURE__ */ jsxs("div", {
2318
- 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"),
2319
- children: [/* @__PURE__ */ jsx("dt", {
2320
- className: cn("text-muted-foreground font-medium w-1/3 shrink-0", SIZE_LABEL[size]),
2321
- children: item.label
2322
- }), /* @__PURE__ */ jsx("dd", {
2323
- className: cn("text-foreground flex-1 min-w-0", SIZE_VALUE[size], item.className),
2324
- children: item.render ? item.render() : item.value ?? /* @__PURE__ */ jsx("span", {
2325
- className: "text-muted-foreground/50",
2326
- children: "-"
2327
- })
2328
- })]
2329
- }, index))
2330
- });
2331
- }
2332
- function InlineLayout({ items, columns, size, bordered }) {
2333
- return /* @__PURE__ */ jsx("div", {
2334
- className: cn("grid gap-x-6 gap-y-2", COLUMN_CLASSES[columns], bordered && "p-4"),
2335
- children: items.map((item, index) => /* @__PURE__ */ jsxs("div", {
2336
- className: cn("flex items-center justify-between gap-2 py-1", item.fullWidth && columns > 1 && "col-span-full"),
2337
- children: [/* @__PURE__ */ jsx("span", {
2338
- className: cn("text-muted-foreground", SIZE_LABEL[size]),
2339
- children: item.label
2340
- }), /* @__PURE__ */ jsx("span", {
2341
- className: cn("text-foreground font-medium text-right", SIZE_VALUE[size], item.className),
2342
- children: item.render ? item.render() : item.value ?? "-"
2343
- })]
2344
- }, index))
2345
- });
2346
- }
2347
- function DetailItem({ label, children, value, className, labelClassName, layout = "stacked" }) {
2348
- const content = children ?? value ?? /* @__PURE__ */ jsx("span", {
2349
- className: "text-muted-foreground/50",
2350
- children: "-"
2351
- });
2352
- if (layout === "horizontal") return /* @__PURE__ */ jsxs("div", {
2353
- className: cn("flex items-start gap-4 py-3", className),
2354
- children: [/* @__PURE__ */ jsx("dt", {
2355
- className: cn("text-sm text-muted-foreground font-medium w-1/3 shrink-0", labelClassName),
2356
- children: label
2357
- }), /* @__PURE__ */ jsx("dd", {
2358
- className: "text-sm text-foreground flex-1 min-w-0",
2359
- children: content
2360
- })]
2361
- });
2362
- if (layout === "inline") return /* @__PURE__ */ jsxs("div", {
2363
- className: cn("flex items-center justify-between gap-2 py-1", className),
2364
- children: [/* @__PURE__ */ jsx("span", {
2365
- className: cn("text-sm text-muted-foreground", labelClassName),
2366
- children: label
2367
- }), /* @__PURE__ */ jsx("span", {
2368
- className: "text-sm text-foreground font-medium text-right",
2369
- children: content
2370
- })]
2371
- });
2372
- return /* @__PURE__ */ jsxs("div", {
2373
- className: cn("space-y-1", className),
2374
- children: [/* @__PURE__ */ jsx("dt", {
2375
- className: cn("text-sm text-muted-foreground font-medium", labelClassName),
2376
- children: label
2377
- }), /* @__PURE__ */ jsx("dd", {
2378
- className: "text-sm text-foreground",
2379
- children: content
2380
- })]
2381
- });
2382
- }
2383
-
2384
- //#endregion
2385
- //#region src/components/animated-wrapper.tsx
2386
- /** Tailwind utility class for each animation — presence in dist ensures @keyframes emission via @source */
2387
- const ANIMATION_CLASSES = {
2388
- fadeIn: "animate-fade-in",
2389
- fadeInUp: "animate-fade-in-up",
2390
- scaleIn: "animate-scale-in",
2391
- slideInLeft: "animate-slide-in-left",
2392
- slideInRight: "animate-slide-in-right",
2393
- slideInUp: "animate-slide-in-up",
2394
- slideInDown: "animate-slide-in-down"
2395
- };
2396
- const SLIDE_MAP = {
2397
- left: "slideInLeft",
2398
- right: "slideInRight",
2399
- up: "slideInUp",
2400
- down: "slideInDown"
2401
- };
2402
- /**
2403
- * useInView — observe when an element enters the viewport.
2404
- *
2405
- * @example
2406
- * ```tsx
2407
- * const ref = useRef<HTMLDivElement>(null);
2408
- * const isInView = useInView(ref, { once: true, margin: "-100px" });
2409
- * return <div ref={ref}>{isInView ? "Visible!" : "Hidden"}</div>;
2410
- * ```
2411
- */
2412
- function useInView(ref, options = {}) {
2413
- const { margin = "0px", once = true, enabled = true } = options;
2414
- const [inView, setInView] = useState(false);
2415
- useEffect(() => {
2416
- if (!enabled) return;
2417
- const el = ref.current;
2418
- if (!el) return;
2419
- const observer = new IntersectionObserver(([entry]) => {
2420
- if (entry.isIntersecting) {
2421
- setInView(true);
2422
- if (once) observer.unobserve(el);
2423
- } else if (!once) setInView(false);
2424
- }, { rootMargin: margin });
2425
- observer.observe(el);
2426
- return () => observer.disconnect();
2427
- }, [
2428
- enabled,
2429
- margin,
2430
- once
2431
- ]);
2432
- return inView;
2433
- }
2434
- function useAnimationState(opts) {
2435
- const ref = useRef(null);
2436
- const shouldAnimate = !opts.disabled;
2437
- const isInView = useInView(ref, {
2438
- margin: opts.inViewMargin,
2439
- once: opts.once,
2440
- enabled: !!opts.inView && shouldAnimate
2441
- });
2442
- return {
2443
- ref,
2444
- shouldAnimate,
2445
- active: shouldAnimate && (!opts.inView || isInView)
2446
- };
2447
- }
2448
- /** Per-instance timing overrides — only emitted when different from theme defaults */
2449
- function animTimingStyle(delay, duration) {
2450
- if (delay === 0 && duration === 600) return void 0;
2451
- return {
2452
- ...duration !== 600 ? { animationDuration: `${duration}ms` } : {},
2453
- ...delay > 0 ? { animationDelay: `${delay}ms` } : {}
2454
- };
2455
- }
2456
- function AnimateBase({ animation, children, delay = 0, duration = 600, inView = false, inViewMargin, once = true, disabled = false, className, as = "div" }) {
2457
- const { ref, shouldAnimate, active } = useAnimationState({
2458
- inView,
2459
- inViewMargin,
2460
- once,
2461
- disabled
2462
- });
2463
- return createElement(as, {
2464
- ref,
2465
- "data-fluid-animate": shouldAnimate ? "" : void 0,
2466
- className: cn(shouldAnimate && "opacity-0", active && ANIMATION_CLASSES[animation], className),
2467
- style: active ? animTimingStyle(delay, duration) : void 0
2468
- }, children);
2469
- }
2470
- /** Fade in with opacity transition */
2471
- function FadeIn(props) {
2472
- return /* @__PURE__ */ jsx(AnimateBase, {
2473
- animation: "fadeIn",
2474
- ...props
2475
- });
2476
- }
2477
- /** Fade in with upward motion */
2478
- function FadeInUp(props) {
2479
- return /* @__PURE__ */ jsx(AnimateBase, {
2480
- animation: "fadeInUp",
2481
- ...props
2482
- });
2483
- }
2484
- /** Scale up into view */
2485
- function ScaleIn(props) {
2486
- return /* @__PURE__ */ jsx(AnimateBase, {
2487
- animation: "scaleIn",
2488
- ...props
2489
- });
2490
- }
2491
- /** Slide in from a specified direction */
2492
- function SlideIn({ direction = "left", ...props }) {
2493
- return /* @__PURE__ */ jsx(AnimateBase, {
2494
- animation: SLIDE_MAP[direction],
2495
- ...props
2496
- });
2497
- }
2498
- function StaggerChildren({ children, animation = "fadeInUp", staggerDelay = 100, initialDelay = 0, duration = 600, inView = false, inViewMargin, once = true, disabled = false, className, childClassName, as = "div" }) {
2499
- const { ref, shouldAnimate, active } = useAnimationState({
2500
- inView,
2501
- inViewMargin,
2502
- once,
2503
- disabled
2504
- });
2505
- const items = Children.toArray(children);
2506
- return createElement(as, {
2507
- ref,
2508
- className
2509
- }, items.map((child, i) => /* @__PURE__ */ jsx("div", {
2510
- "data-fluid-animate": shouldAnimate ? "" : void 0,
2511
- className: cn(shouldAnimate && "opacity-0", active && ANIMATION_CLASSES[animation], childClassName),
2512
- style: active ? animTimingStyle(initialDelay + i * staggerDelay, duration) : void 0,
2513
- children: child
2514
- }, i)));
2515
- }
2516
- function AnimatedText({ text, as = "div", animation = "fadeInUp", splitBy = "word", staggerDelay = 80, delay = 0, duration = 600, inView = false, inViewMargin, once = true, disabled = false, className, segmentClassName }) {
2517
- const { ref, shouldAnimate, active } = useAnimationState({
2518
- inView,
2519
- inViewMargin,
2520
- once,
2521
- disabled
2522
- });
2523
- const segments = splitBy === "word" ? text.split(" ") : text.split("");
2524
- let animIndex = 0;
2525
- return createElement(as, {
2526
- ref,
2527
- className
2528
- }, segments.map((segment, i) => {
2529
- if (splitBy === "character" && segment === " ") return /* @__PURE__ */ jsx(Fragment$1, { children: "\xA0" }, i);
2530
- const idx = animIndex++;
2531
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [splitBy === "word" && i > 0 && " ", /* @__PURE__ */ jsx("span", {
2532
- "data-fluid-animate": shouldAnimate ? "" : void 0,
2533
- className: cn("inline-block", shouldAnimate && "opacity-0", active && ANIMATION_CLASSES[animation], segmentClassName),
2534
- style: active ? animTimingStyle(delay + idx * staggerDelay, duration) : void 0,
2535
- children: segment
2536
- })] }, i);
2537
- }));
2538
- }
2539
- function easeOutCubic(t) {
2540
- return 1 - Math.pow(1 - t, 3);
2541
- }
2542
- 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" }) {
2543
- const ref = useRef(null);
2544
- const isInView = useInView(ref, {
2545
- margin: inViewMargin,
2546
- once,
2547
- enabled: inView && !disabled
2548
- });
2549
- const active = !disabled && (!inView || isInView);
2550
- const [count, setCount] = useState(from);
2551
- const hasStarted = useRef(false);
2552
- useEffect(() => {
2553
- if (disabled) {
2554
- setCount(to);
2555
- return;
2556
- }
2557
- if (!active || hasStarted.current) return;
2558
- hasStarted.current = true;
2559
- if (typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
2560
- setCount(to);
2561
- return;
2562
- }
2563
- const timeout = setTimeout(() => {
2564
- const start = performance.now();
2565
- const step = (now) => {
2566
- const elapsed = now - start;
2567
- const progress = Math.min(elapsed / duration, 1);
2568
- const eased = easeOutCubic(progress);
2569
- const current = from + (to - from) * eased;
2570
- setCount(decimals > 0 ? Number(current.toFixed(decimals)) : Math.round(current));
2571
- if (progress < 1) requestAnimationFrame(step);
2572
- };
2573
- requestAnimationFrame(step);
2574
- }, delay);
2575
- return () => clearTimeout(timeout);
2576
- }, [
2577
- active,
2578
- disabled,
2579
- from,
2580
- to,
2581
- duration,
2582
- delay,
2583
- decimals
2584
- ]);
2585
- const formatValue = (v) => {
2586
- if (formatter) return formatter(v);
2587
- if (locale) return v.toLocaleString(locale, {
2588
- minimumFractionDigits: decimals,
2589
- maximumFractionDigits: decimals
2590
- });
2591
- if (decimals > 0) return v.toFixed(decimals);
2592
- return String(v);
2593
- };
2594
- return createElement(as, {
2595
- ref,
2596
- className
2597
- }, /* @__PURE__ */ jsxs(Fragment, { children: [
2598
- prefix,
2599
- formatValue(count),
2600
- suffix
2601
- ] }));
2602
- }
2603
-
2604
- //#endregion
2605
- 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 };
1494
+ 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, PrintableView, RadioDropdown, ResponsiveSplitLayout, ScaleIn, SelectDropdown, SheetWrapper, SimpleTable, SlideIn, StaggerChildren, StatsCard, StatusBanner, StepContent, Stepper, SubmitFooter, TabContent, TabTrigger, TableWrapper, TabsWrapper, Thumbnail, Timeline, TooltipWrapper, printDocument, useInView };