@moontra/moonui-pro 2.20.1 → 2.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/index.d.ts +691 -261
  2. package/dist/index.mjs +7418 -4934
  3. package/package.json +4 -3
  4. package/scripts/postbuild.js +27 -0
  5. package/src/components/advanced-chart/index.tsx +5 -1
  6. package/src/components/advanced-forms/index.tsx +175 -16
  7. package/src/components/calendar/event-dialog.tsx +18 -13
  8. package/src/components/calendar/index.tsx +197 -50
  9. package/src/components/dashboard/dashboard-grid.tsx +21 -3
  10. package/src/components/dashboard/types.ts +3 -0
  11. package/src/components/dashboard/widgets/activity-feed.tsx +6 -1
  12. package/src/components/dashboard/widgets/comparison-widget.tsx +177 -0
  13. package/src/components/dashboard/widgets/index.ts +5 -0
  14. package/src/components/dashboard/widgets/metric-card.tsx +21 -1
  15. package/src/components/dashboard/widgets/progress-widget.tsx +113 -0
  16. package/src/components/error-boundary/index.tsx +160 -37
  17. package/src/components/form-wizard/form-wizard-context.tsx +54 -26
  18. package/src/components/form-wizard/form-wizard-progress.tsx +33 -2
  19. package/src/components/form-wizard/types.ts +2 -1
  20. package/src/components/github-stars/hooks.ts +1 -0
  21. package/src/components/github-stars/variants.tsx +3 -1
  22. package/src/components/health-check/index.tsx +14 -14
  23. package/src/components/hover-card-3d/index.tsx +2 -3
  24. package/src/components/index.ts +5 -3
  25. package/src/components/kanban/kanban.tsx +23 -18
  26. package/src/components/license-error/index.tsx +2 -0
  27. package/src/components/magnetic-button/index.tsx +56 -7
  28. package/src/components/memory-efficient-data/index.tsx +117 -115
  29. package/src/components/navbar/index.tsx +781 -0
  30. package/src/components/performance-debugger/index.tsx +62 -38
  31. package/src/components/performance-monitor/index.tsx +47 -33
  32. package/src/components/phone-number-input/index.tsx +32 -27
  33. package/src/components/phone-number-input/phone-number-input-simple.tsx +167 -0
  34. package/src/components/rich-text-editor/index.tsx +26 -28
  35. package/src/components/rich-text-editor/slash-commands-extension.ts +15 -5
  36. package/src/components/sidebar/index.tsx +32 -13
  37. package/src/components/timeline/index.tsx +84 -49
  38. package/src/components/ui/accordion.tsx +550 -42
  39. package/src/components/ui/avatar.tsx +2 -0
  40. package/src/components/ui/badge.tsx +2 -0
  41. package/src/components/ui/breadcrumb.tsx +2 -0
  42. package/src/components/ui/button.tsx +39 -33
  43. package/src/components/ui/card.tsx +2 -0
  44. package/src/components/ui/collapsible.tsx +546 -50
  45. package/src/components/ui/command.tsx +790 -67
  46. package/src/components/ui/dialog.tsx +510 -92
  47. package/src/components/ui/dropdown-menu.tsx +540 -52
  48. package/src/components/ui/index.ts +37 -5
  49. package/src/components/ui/input.tsx +2 -0
  50. package/src/components/ui/magnetic-button.tsx +1 -1
  51. package/src/components/ui/media-gallery.tsx +1 -2
  52. package/src/components/ui/navigation-menu.tsx +130 -0
  53. package/src/components/ui/pagination.tsx +2 -0
  54. package/src/components/ui/select.tsx +6 -2
  55. package/src/components/ui/spotlight-card.tsx +1 -1
  56. package/src/components/ui/table.tsx +2 -0
  57. package/src/components/ui/tabs-pro.tsx +542 -0
  58. package/src/components/ui/tabs.tsx +23 -167
  59. package/src/components/ui/toggle.tsx +12 -12
  60. package/src/index.ts +11 -3
  61. package/src/styles/index.css +596 -0
  62. package/src/use-performance-optimizer.ts +1 -1
  63. package/src/utils/chart-helpers.ts +1 -1
  64. package/src/__tests__/use-intersection-observer.test.tsx +0 -216
  65. package/src/__tests__/use-local-storage.test.tsx +0 -174
  66. package/src/__tests__/use-pro-access.test.tsx +0 -183
  67. package/src/components/advanced-chart/advanced-chart.test.tsx +0 -281
  68. package/src/components/data-table/data-table.test.tsx +0 -187
  69. package/src/components/enhanced/badge.tsx +0 -191
  70. package/src/components/enhanced/button.tsx +0 -362
  71. package/src/components/enhanced/card.tsx +0 -266
  72. package/src/components/enhanced/dialog.tsx +0 -246
  73. package/src/components/enhanced/index.ts +0 -4
  74. package/src/components/file-upload/file-upload.test.tsx +0 -243
  75. package/src/components/rich-text-editor/index-old-backup.tsx +0 -437
  76. package/src/types/moonui.d.ts +0 -22
@@ -0,0 +1,542 @@
1
+ "use client"
2
+
3
+ import * as React from "react";
4
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
5
+ import { cva, type VariantProps } from "class-variance-authority";
6
+ import { motion, AnimatePresence, type Variants } from "framer-motion";
7
+ import { X, Plus, ChevronLeft, ChevronRight, MoreHorizontal, Loader2 } from "lucide-react";
8
+ import { cn } from "../../lib/utils";
9
+ import { Button } from "./button";
10
+ import {
11
+ DropdownMenu,
12
+ DropdownMenuContent,
13
+ DropdownMenuItem,
14
+ DropdownMenuTrigger,
15
+ } from "./dropdown-menu";
16
+
17
+ // Animation variants
18
+ const contentVariants: Record<string, Variants> = {
19
+ fade: {
20
+ initial: { opacity: 0 },
21
+ animate: { opacity: 1 },
22
+ exit: { opacity: 0 },
23
+ },
24
+ slide: {
25
+ initial: { x: 20, opacity: 0 },
26
+ animate: { x: 0, opacity: 1 },
27
+ exit: { x: -20, opacity: 0 },
28
+ },
29
+ scale: {
30
+ initial: { scale: 0.95, opacity: 0 },
31
+ animate: { scale: 1, opacity: 1 },
32
+ exit: { scale: 1.05, opacity: 0 },
33
+ },
34
+ flip: {
35
+ initial: { rotateY: 90, opacity: 0 },
36
+ animate: { rotateY: 0, opacity: 1 },
37
+ exit: { rotateY: -90, opacity: 0 },
38
+ },
39
+ morph: {
40
+ initial: { scale: 0.8, opacity: 0, filter: "blur(10px)" },
41
+ animate: { scale: 1, opacity: 1, filter: "blur(0px)" },
42
+ exit: { scale: 1.2, opacity: 0, filter: "blur(10px)" },
43
+ },
44
+ };
45
+
46
+ // Tab item type
47
+ interface TabItem {
48
+ value: string;
49
+ label: React.ReactNode;
50
+ icon?: React.ReactNode;
51
+ badge?: React.ReactNode;
52
+ closeable?: boolean;
53
+ disabled?: boolean;
54
+ content?: React.ReactNode;
55
+ lazy?: boolean;
56
+ tooltip?: string;
57
+ }
58
+
59
+ // Pro Tabs Root
60
+ interface MoonUITabsProProps extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>, 'orientation'> {
61
+ /** Visual variant */
62
+ variant?: "default" | "pills" | "underline" | "cards" | "minimal" | "gradient" | "glassmorphism" | "neon";
63
+ /** Animation mode */
64
+ animationMode?: "fade" | "slide" | "scale" | "flip" | "morph" | "none";
65
+ /** Orientation */
66
+ orientation?: "horizontal" | "vertical";
67
+ /** Allow closing tabs */
68
+ closeable?: boolean;
69
+ /** Allow adding tabs */
70
+ addable?: boolean;
71
+ /** Allow reordering tabs */
72
+ draggable?: boolean;
73
+ /** Persist state to localStorage */
74
+ persistKey?: string;
75
+ /** Sync with URL */
76
+ urlSync?: boolean;
77
+ /** Lazy load tab content */
78
+ lazy?: boolean;
79
+ /** Tab items for dynamic tabs */
80
+ items?: TabItem[];
81
+ /** Callback when tabs change */
82
+ onTabsChange?: (items: TabItem[]) => void;
83
+ /** Callback when tab is closed */
84
+ onTabClose?: (value: string) => void;
85
+ /** Callback when tab is added */
86
+ onTabAdd?: () => void;
87
+ /** Loading state */
88
+ loading?: boolean;
89
+ /** Swipeable on mobile */
90
+ swipeable?: boolean;
91
+ /** Show scroll buttons */
92
+ scrollable?: boolean;
93
+ /** Analytics callback */
94
+ onAnalytics?: (event: string, data: any) => void;
95
+ /** Tab validation before switching */
96
+ onBeforeChange?: (from: string, to: string) => boolean | Promise<boolean>;
97
+ /** Keyboard shortcuts */
98
+ shortcuts?: boolean;
99
+ /** Max tabs */
100
+ maxTabs?: number;
101
+ /** Tab groups */
102
+ groups?: Array<{ label: string; tabs: string[] }>;
103
+ className?: string;
104
+ children?: React.ReactNode;
105
+ }
106
+
107
+ const MoonUITabsPro = React.forwardRef<
108
+ React.ElementRef<typeof TabsPrimitive.Root>,
109
+ MoonUITabsProProps
110
+ >(({
111
+ variant = "default",
112
+ animationMode = "fade",
113
+ orientation = "horizontal",
114
+ closeable = false,
115
+ addable = false,
116
+ draggable = false,
117
+ persistKey,
118
+ urlSync = false,
119
+ lazy = false,
120
+ items: initialItems = [],
121
+ onTabsChange,
122
+ onTabClose,
123
+ onTabAdd,
124
+ loading = false,
125
+ swipeable = false,
126
+ scrollable = false,
127
+ onAnalytics,
128
+ onBeforeChange,
129
+ shortcuts = false,
130
+ maxTabs,
131
+ groups,
132
+ className,
133
+ children,
134
+ value: controlledValue,
135
+ defaultValue,
136
+ onValueChange,
137
+ ...props
138
+ }, ref) => {
139
+ const [items, setItems] = React.useState<TabItem[]>(initialItems);
140
+ const [localValue, setLocalValue] = React.useState(() => {
141
+ // Check persistence
142
+ if (persistKey && typeof window !== 'undefined') {
143
+ const stored = localStorage.getItem(`tabs-${persistKey}`);
144
+ if (stored) {
145
+ const parsed = JSON.parse(stored);
146
+ return parsed.activeTab || defaultValue || items[0]?.value;
147
+ }
148
+ }
149
+ // Check URL
150
+ if (urlSync && typeof window !== 'undefined') {
151
+ const params = new URLSearchParams(window.location.search);
152
+ const tabParam = params.get('tab');
153
+ if (tabParam) return tabParam;
154
+ }
155
+ return defaultValue || items[0]?.value;
156
+ });
157
+
158
+ const [loadedTabs, setLoadedTabs] = React.useState<Set<string>>(new Set());
159
+ const [isChanging, setIsChanging] = React.useState(false);
160
+ const scrollRef = React.useRef<HTMLDivElement>(null);
161
+
162
+ const value = controlledValue !== undefined ? controlledValue : localValue;
163
+
164
+ // Handle value change
165
+ const handleValueChange = React.useCallback(async (newValue: string) => {
166
+ if (loading || isChanging) return;
167
+
168
+ // Validation
169
+ if (onBeforeChange) {
170
+ setIsChanging(true);
171
+ const canChange = await onBeforeChange(value || '', newValue);
172
+ setIsChanging(false);
173
+ if (!canChange) return;
174
+ }
175
+
176
+ setLocalValue(newValue);
177
+ onValueChange?.(newValue);
178
+
179
+ // Track lazy loading
180
+ if (lazy && !loadedTabs.has(newValue)) {
181
+ setLoadedTabs(prev => new Set([...prev, newValue]));
182
+ }
183
+
184
+ // Analytics
185
+ onAnalytics?.('tab_switch', { from: value, to: newValue });
186
+
187
+ // Persistence
188
+ if (persistKey && typeof window !== 'undefined') {
189
+ localStorage.setItem(`tabs-${persistKey}`, JSON.stringify({
190
+ activeTab: newValue,
191
+ tabs: items
192
+ }));
193
+ }
194
+
195
+ // URL sync
196
+ if (urlSync && typeof window !== 'undefined') {
197
+ const params = new URLSearchParams(window.location.search);
198
+ params.set('tab', newValue);
199
+ window.history.replaceState({}, '', `${window.location.pathname}?${params}`);
200
+ }
201
+ }, [value, loading, isChanging, onBeforeChange, onValueChange, lazy, loadedTabs, onAnalytics, persistKey, items, urlSync]);
202
+
203
+ // Handle tab close
204
+ const handleTabClose = React.useCallback((tabValue: string, e: React.MouseEvent) => {
205
+ e.stopPropagation();
206
+
207
+ const newItems = items.filter(item => item.value !== tabValue);
208
+ setItems(newItems);
209
+ onTabsChange?.(newItems);
210
+ onTabClose?.(tabValue);
211
+ onAnalytics?.('tab_close', { value: tabValue });
212
+
213
+ // If closing active tab, switch to first available
214
+ if (value === tabValue && newItems.length > 0) {
215
+ handleValueChange(newItems[0].value);
216
+ }
217
+ }, [items, value, onTabsChange, onTabClose, onAnalytics, handleValueChange]);
218
+
219
+ // Handle tab add
220
+ const handleTabAdd = React.useCallback(() => {
221
+ if (maxTabs && items.length >= maxTabs) {
222
+ onAnalytics?.('tab_add_blocked', { reason: 'max_tabs' });
223
+ return;
224
+ }
225
+
226
+ onTabAdd?.();
227
+ onAnalytics?.('tab_add', { count: items.length + 1 });
228
+ }, [items.length, maxTabs, onTabAdd, onAnalytics]);
229
+
230
+ // Keyboard shortcuts
231
+ React.useEffect(() => {
232
+ if (!shortcuts) return;
233
+
234
+ const handleKeyDown = (e: KeyboardEvent) => {
235
+ // Ctrl/Cmd + number to switch tabs
236
+ if ((e.metaKey || e.ctrlKey) && e.key >= '1' && e.key <= '9') {
237
+ e.preventDefault();
238
+ const index = parseInt(e.key) - 1;
239
+ if (items[index]) {
240
+ handleValueChange(items[index].value);
241
+ }
242
+ }
243
+ // Ctrl/Cmd + W to close current tab
244
+ if ((e.metaKey || e.ctrlKey) && e.key === 'w' && closeable) {
245
+ e.preventDefault();
246
+ const currentTab = items.find(item => item.value === value);
247
+ if (currentTab?.closeable !== false) {
248
+ handleTabClose(value || '', new MouseEvent('click') as any);
249
+ }
250
+ }
251
+ // Ctrl/Cmd + T to add new tab
252
+ if ((e.metaKey || e.ctrlKey) && e.key === 't' && addable) {
253
+ e.preventDefault();
254
+ handleTabAdd();
255
+ }
256
+ };
257
+
258
+ document.addEventListener('keydown', handleKeyDown);
259
+ return () => document.removeEventListener('keydown', handleKeyDown);
260
+ }, [shortcuts, items, value, closeable, addable, handleValueChange, handleTabClose, handleTabAdd]);
261
+
262
+ // Scroll buttons
263
+ const scrollLeft = () => {
264
+ if (scrollRef.current) {
265
+ scrollRef.current.scrollBy({ left: -200, behavior: 'smooth' });
266
+ }
267
+ };
268
+
269
+ const scrollRight = () => {
270
+ if (scrollRef.current) {
271
+ scrollRef.current.scrollBy({ left: 200, behavior: 'smooth' });
272
+ }
273
+ };
274
+
275
+ return (
276
+ <div className={cn(
277
+ "relative w-full",
278
+ variant === "gradient" && "bg-gradient-to-r from-primary/10 to-secondary/10 rounded-lg p-1",
279
+ variant === "glassmorphism" && "backdrop-blur-xl bg-white/10 dark:bg-black/10 border border-white/20 dark:border-white/10 rounded-lg p-1",
280
+ variant === "neon" && "bg-black rounded-lg p-1 shadow-[0_0_20px_rgba(139,92,246,0.3)]",
281
+ className
282
+ )}>
283
+ {loading && (
284
+ <div className="absolute inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm rounded-lg">
285
+ <Loader2 className="h-6 w-6 animate-spin text-primary" />
286
+ </div>
287
+ )}
288
+
289
+ <TabsPrimitive.Root
290
+ ref={ref}
291
+ value={value}
292
+ onValueChange={handleValueChange}
293
+ orientation={orientation}
294
+ {...props}
295
+ >
296
+ {/* If items are provided, render items-based tabs */}
297
+ {items.length > 0 ? (
298
+ <>
299
+ <div className={cn(
300
+ "relative flex items-center",
301
+ orientation === "vertical" && "flex-col items-start"
302
+ )}>
303
+ {/* Scroll button left */}
304
+ {scrollable && orientation === "horizontal" && (
305
+ <Button
306
+ variant="ghost"
307
+ size="sm"
308
+ className="h-8 w-8 p-0 absolute left-0 z-10"
309
+ onClick={scrollLeft}
310
+ >
311
+ <ChevronLeft className="h-4 w-4" />
312
+ </Button>
313
+ )}
314
+
315
+ {/* Tabs List */}
316
+ <div
317
+ ref={scrollRef}
318
+ className={cn(
319
+ "flex-1 overflow-x-auto scrollbar-hide",
320
+ scrollable && orientation === "horizontal" && "mx-10"
321
+ )}
322
+ >
323
+ <TabsPrimitive.List
324
+ className={cn(
325
+ "flex items-center gap-1",
326
+ orientation === "vertical" && "flex-col items-start w-full",
327
+ variant === "underline" && "border-b border-border"
328
+ )}
329
+ >
330
+ {items.map((item, index) => (
331
+ <motion.div
332
+ key={item.value}
333
+ layout
334
+ drag={draggable ? orientation === "horizontal" ? "x" : "y" : false}
335
+ dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}
336
+ dragElastic={0.2}
337
+ whileDrag={{ scale: 1.05, zIndex: 50 }}
338
+ className="relative"
339
+ >
340
+ <TabsPrimitive.Trigger
341
+ value={item.value}
342
+ disabled={item.disabled}
343
+ className={cn(
344
+ "relative inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
345
+ // Variant styles
346
+ variant === "default" && "data-[state=active]:bg-background data-[state=active]:shadow-sm",
347
+ variant === "pills" && "rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground",
348
+ variant === "underline" && "rounded-none border-b-2 border-transparent data-[state=active]:border-primary",
349
+ variant === "cards" && "bg-muted/50 data-[state=active]:bg-background data-[state=active]:shadow-md",
350
+ variant === "minimal" && "hover:bg-muted/50 data-[state=active]:bg-transparent data-[state=active]:underline",
351
+ variant === "gradient" && "data-[state=active]:bg-gradient-to-r data-[state=active]:from-primary data-[state=active]:to-secondary data-[state=active]:text-white",
352
+ variant === "glassmorphism" && "backdrop-blur-md data-[state=active]:bg-white/20 dark:data-[state=active]:bg-white/10",
353
+ variant === "neon" && "text-purple-400 data-[state=active]:text-white data-[state=active]:shadow-[0_0_10px_rgba(139,92,246,0.8)]",
354
+ orientation === "vertical" && "w-full justify-start"
355
+ )}
356
+ >
357
+ {item.icon && <span className="mr-2">{item.icon}</span>}
358
+ {item.label}
359
+ {item.badge && <span className="ml-2">{item.badge}</span>}
360
+ {closeable && item.closeable !== false && (
361
+ <button
362
+ onClick={(e) => handleTabClose(item.value, e)}
363
+ className="ml-2 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
364
+ >
365
+ <X className="h-3 w-3" />
366
+ </button>
367
+ )}
368
+ </TabsPrimitive.Trigger>
369
+
370
+ {/* Active indicator animation */}
371
+ {value === item.value && animationMode !== "none" && (
372
+ <motion.div
373
+ layoutId="active-tab"
374
+ className={cn(
375
+ "absolute inset-0 -z-10",
376
+ variant === "default" && "bg-background shadow-sm rounded-md",
377
+ variant === "pills" && "bg-primary rounded-full",
378
+ variant === "underline" && "bottom-0 h-0.5 bg-primary"
379
+ )}
380
+ transition={{
381
+ type: "spring",
382
+ stiffness: 500,
383
+ damping: 30
384
+ }}
385
+ />
386
+ )}
387
+ </motion.div>
388
+ ))}
389
+
390
+ {/* Add tab button */}
391
+ {addable && (
392
+ <Button
393
+ variant="ghost"
394
+ size="sm"
395
+ onClick={handleTabAdd}
396
+ className="h-8 w-8 p-0 ml-2"
397
+ disabled={maxTabs ? items.length >= maxTabs : false}
398
+ >
399
+ <Plus className="h-4 w-4" />
400
+ </Button>
401
+ )}
402
+ </TabsPrimitive.List>
403
+ </div>
404
+
405
+ {/* Scroll button right */}
406
+ {scrollable && orientation === "horizontal" && (
407
+ <Button
408
+ variant="ghost"
409
+ size="sm"
410
+ className="h-8 w-8 p-0 absolute right-0 z-10"
411
+ onClick={scrollRight}
412
+ >
413
+ <ChevronRight className="h-4 w-4" />
414
+ </Button>
415
+ )}
416
+
417
+ {/* Overflow menu for hidden tabs */}
418
+ {items.length > 5 && (
419
+ <DropdownMenu>
420
+ <DropdownMenuTrigger asChild>
421
+ <Button variant="ghost" size="sm" className="h-8 w-8 p-0 ml-2">
422
+ <MoreHorizontal className="h-4 w-4" />
423
+ </Button>
424
+ </DropdownMenuTrigger>
425
+ <DropdownMenuContent align="end">
426
+ {items.slice(5).map(item => (
427
+ <DropdownMenuItem
428
+ key={item.value}
429
+ onClick={() => handleValueChange(item.value)}
430
+ >
431
+ {item.icon && <span className="mr-2">{item.icon}</span>}
432
+ {item.label}
433
+ </DropdownMenuItem>
434
+ ))}
435
+ </DropdownMenuContent>
436
+ </DropdownMenu>
437
+ )}
438
+ </div>
439
+
440
+ {/* Tab contents with animations */}
441
+ {animationMode !== "none" ? (
442
+ <AnimatePresence mode="wait">
443
+ {items.map(item => {
444
+ if (value !== item.value) return null;
445
+
446
+ return (
447
+ <TabsPrimitive.Content
448
+ key={item.value}
449
+ value={item.value}
450
+ forceMount
451
+ className="mt-4 focus-visible:outline-none"
452
+ >
453
+ <motion.div
454
+ initial="initial"
455
+ animate="animate"
456
+ exit="exit"
457
+ variants={contentVariants[animationMode]}
458
+ transition={{ duration: 0.3 }}
459
+ >
460
+ {item.content || children}
461
+ </motion.div>
462
+ </TabsPrimitive.Content>
463
+ );
464
+ })}
465
+ </AnimatePresence>
466
+ ) : (
467
+ items.map(item => (
468
+ <TabsPrimitive.Content
469
+ key={item.value}
470
+ value={item.value}
471
+ className="mt-4 focus-visible:outline-none"
472
+ >
473
+ {item.content || children}
474
+ </TabsPrimitive.Content>
475
+ ))
476
+ )}
477
+ </>
478
+ ) : (
479
+ /* Otherwise, render children-based tabs */
480
+ children
481
+ )}
482
+ </TabsPrimitive.Root>
483
+ </div>
484
+ );
485
+ });
486
+
487
+ MoonUITabsPro.displayName = "MoonUITabsPro";
488
+
489
+ // Additional Pro Tab Components
490
+ const MoonUITabsListPro = React.forwardRef<
491
+ React.ElementRef<typeof TabsPrimitive.List>,
492
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
493
+ >(({ className, ...props }, ref) => (
494
+ <TabsPrimitive.List
495
+ ref={ref}
496
+ className={cn(
497
+ "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
498
+ className
499
+ )}
500
+ {...props}
501
+ />
502
+ ));
503
+ MoonUITabsListPro.displayName = "MoonUITabsListPro";
504
+
505
+ const MoonUITabsTriggerPro = React.forwardRef<
506
+ React.ElementRef<typeof TabsPrimitive.Trigger>,
507
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
508
+ >(({ className, ...props }, ref) => (
509
+ <TabsPrimitive.Trigger
510
+ ref={ref}
511
+ className={cn(
512
+ "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
513
+ className
514
+ )}
515
+ {...props}
516
+ />
517
+ ));
518
+ MoonUITabsTriggerPro.displayName = "MoonUITabsTriggerPro";
519
+
520
+ const MoonUITabsContentPro = React.forwardRef<
521
+ React.ElementRef<typeof TabsPrimitive.Content>,
522
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
523
+ >(({ className, ...props }, ref) => (
524
+ <TabsPrimitive.Content
525
+ ref={ref}
526
+ className={cn(
527
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
528
+ className
529
+ )}
530
+ {...props}
531
+ />
532
+ ));
533
+ MoonUITabsContentPro.displayName = "MoonUITabsContentPro";
534
+
535
+ export {
536
+ MoonUITabsPro,
537
+ MoonUITabsListPro,
538
+ MoonUITabsTriggerPro,
539
+ MoonUITabsContentPro,
540
+ type TabItem,
541
+ type MoonUITabsProProps
542
+ };