@moontra/moonui-pro 2.20.0 → 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 +7419 -4935
  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 +13 -13
  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
@@ -3,56 +3,371 @@
3
3
  import * as React from "react"
4
4
  import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
5
5
  import { cva, type VariantProps } from "class-variance-authority"
6
- import { ChevronDown } from "lucide-react"
6
+ import {
7
+ ChevronDown,
8
+ ChevronRight,
9
+ ChevronUp,
10
+ Loader2,
11
+ ExternalLink,
12
+ AlertCircle,
13
+ CheckCircle2,
14
+ XCircle,
15
+ Info,
16
+ Clock,
17
+ Hash
18
+ } from "lucide-react"
7
19
 
8
20
  import { cn } from "../../lib/utils"
9
21
 
10
22
  /**
11
- * Collapsible (Daraltılabilir) Bileşeni
23
+ * MoonUICollapsiblePro - Advanced Collapsible Component
12
24
  *
13
- * İçeriği genişletilip daraltılabilen hafif bir bileşendir.
14
- * Tema sistemiyle tam entegre, erişilebilir ve özelleştirilebilir.
25
+ * A feature-rich collapsible component with professional features:
26
+ * - Multiple visual variants (elevated, bordered, gradient, glassmorphism, card)
27
+ * - Size options (xs, sm, md, lg, xl)
28
+ * - Animation modes (spring, smooth, fade, bounce, slide)
29
+ * - Loading states with skeletons
30
+ * - Icon support (left/right icons, custom chevrons)
31
+ * - Progress indicators
32
+ * - Badge system with variants
33
+ * - Lazy loading for performance
34
+ * - Auto-collapse timer
35
+ * - Keyboard shortcuts
36
+ * - Analytics tracking
37
+ * - Memory persistence
38
+ * - Nested collapsibles support
15
39
  */
16
40
 
17
- const MoonUICollapsiblePro = CollapsiblePrimitive.Root
41
+ // Type definitions
42
+ type CollapsibleSize = "xs" | "sm" | "md" | "lg" | "xl";
43
+ type CollapsibleVariant = "default" | "bordered" | "elevated" | "gradient" | "glassmorphism" | "card";
44
+ type AnimationMode = "spring" | "smooth" | "fade" | "bounce" | "slide";
45
+ type BadgeVariant = "default" | "primary" | "secondary" | "success" | "warning" | "danger" | "info";
18
46
 
19
- const MoonUIcollapsibleTriggerVariantsPro = cva(
20
- "flex w-full items-center justify-between transition-all",
47
+ // Enhanced Collapsible Root component
48
+ interface MoonUICollapsibleProProps {
49
+ /** Visual variant */
50
+ variant?: CollapsibleVariant;
51
+ /** Size preset */
52
+ size?: CollapsibleSize;
53
+ /** Animation mode */
54
+ animationMode?: AnimationMode;
55
+ /** Auto-collapse after X milliseconds */
56
+ autoCollapseAfter?: number;
57
+ /** Analytics tracking callback */
58
+ onToggleChange?: (isOpen: boolean) => void;
59
+ /** Memory persistence key */
60
+ persistKey?: string;
61
+ /** Loading state */
62
+ loading?: boolean;
63
+ /** Progress percentage (0-100) */
64
+ progress?: number;
65
+ /** Badge content */
66
+ badge?: React.ReactNode;
67
+ /** Badge variant */
68
+ badgeVariant?: BadgeVariant;
69
+ /** Custom keyboard shortcut */
70
+ shortcut?: string;
71
+ /** Lazy load content */
72
+ lazy?: boolean;
73
+ /** Additional className */
74
+ className?: string;
75
+ /** Control open state */
76
+ open?: boolean;
77
+ /** Default open state */
78
+ defaultOpen?: boolean;
79
+ /** Callback when open state changes */
80
+ onOpenChange?: (open: boolean) => void;
81
+ /** Children elements */
82
+ children?: React.ReactNode;
83
+ /** Disabled state */
84
+ disabled?: boolean;
85
+ }
86
+
87
+ const MoonUICollapsiblePro = React.forwardRef<
88
+ React.ElementRef<typeof CollapsiblePrimitive.Root>,
89
+ MoonUICollapsibleProProps
90
+ >(({
91
+ className,
92
+ variant = "default",
93
+ size = "md",
94
+ animationMode = "smooth",
95
+ autoCollapseAfter,
96
+ onToggleChange,
97
+ persistKey,
98
+ loading,
99
+ progress,
100
+ badge,
101
+ badgeVariant = "default",
102
+ shortcut,
103
+ lazy,
104
+ open: controlledOpen,
105
+ defaultOpen,
106
+ onOpenChange,
107
+ children,
108
+ disabled
109
+ }, ref) => {
110
+ const [localOpen, setLocalOpen] = React.useState(() => {
111
+ // Check memory persistence
112
+ if (persistKey && typeof window !== 'undefined') {
113
+ const stored = localStorage.getItem(`collapsible-${persistKey}`);
114
+ if (stored !== null) {
115
+ return stored === 'true';
116
+ }
117
+ }
118
+ return defaultOpen || false;
119
+ });
120
+
121
+ const [hasBeenOpened, setHasBeenOpened] = React.useState(!lazy);
122
+
123
+ const isOpen = controlledOpen !== undefined ? controlledOpen : localOpen;
124
+
125
+ const handleOpenChange = React.useCallback((open: boolean) => {
126
+ if (!loading) {
127
+ setLocalOpen(open);
128
+ onOpenChange?.(open);
129
+ onToggleChange?.(open);
130
+
131
+ // Persist state
132
+ if (persistKey && typeof window !== 'undefined') {
133
+ localStorage.setItem(`collapsible-${persistKey}`, String(open));
134
+ }
135
+
136
+ // Track lazy loading
137
+ if (lazy && open && !hasBeenOpened) {
138
+ setHasBeenOpened(true);
139
+ }
140
+
141
+ // Auto-collapse timer
142
+ if (open && autoCollapseAfter) {
143
+ setTimeout(() => {
144
+ setLocalOpen(false);
145
+ onOpenChange?.(false);
146
+ onToggleChange?.(false);
147
+ }, autoCollapseAfter);
148
+ }
149
+ }
150
+ }, [loading, onOpenChange, onToggleChange, persistKey, lazy, hasBeenOpened, autoCollapseAfter]);
151
+
152
+ // Keyboard shortcut handler
153
+ React.useEffect(() => {
154
+ if (shortcut) {
155
+ const handleKeyPress = (e: KeyboardEvent) => {
156
+ const keys = shortcut.toLowerCase().split('+');
157
+ const ctrlKey = keys.includes('ctrl') || keys.includes('cmd');
158
+ const shiftKey = keys.includes('shift');
159
+ const altKey = keys.includes('alt');
160
+ const key = keys[keys.length - 1];
161
+
162
+ if (
163
+ e.ctrlKey === ctrlKey &&
164
+ e.shiftKey === shiftKey &&
165
+ e.altKey === altKey &&
166
+ e.key.toLowerCase() === key
167
+ ) {
168
+ e.preventDefault();
169
+ handleOpenChange(!isOpen);
170
+ }
171
+ };
172
+
173
+ window.addEventListener('keydown', handleKeyPress);
174
+ return () => window.removeEventListener('keydown', handleKeyPress);
175
+ }
176
+ }, [shortcut, isOpen, handleOpenChange]);
177
+
178
+ // Progress ring calculation
179
+ const progressOffset = progress ? 188.4 - (188.4 * progress) / 100 : 188.4;
180
+
181
+ return (
182
+ <div className={cn(
183
+ "relative",
184
+ variant === "bordered" && "border border-border rounded-lg",
185
+ variant === "elevated" && "border border-border rounded-lg shadow-lg hover:shadow-xl transition-shadow",
186
+ variant === "gradient" && "rounded-lg bg-gradient-to-r from-primary/5 via-accent/5 to-secondary/5",
187
+ variant === "glassmorphism" && "rounded-lg backdrop-blur-md bg-white/10 border border-white/20",
188
+ variant === "card" && "border border-border rounded-lg bg-card",
189
+ loading && "opacity-60 pointer-events-none",
190
+ className
191
+ )}>
192
+ {/* Progress indicator */}
193
+ {progress !== undefined && (
194
+ <div className="absolute top-2 right-2 w-6 h-6 z-10">
195
+ <svg className="w-6 h-6 -rotate-90" viewBox="0 0 64 64">
196
+ <circle
197
+ cx="32"
198
+ cy="32"
199
+ r="30"
200
+ fill="none"
201
+ stroke="currentColor"
202
+ strokeWidth="2"
203
+ className="text-muted-foreground/20"
204
+ />
205
+ <circle
206
+ cx="32"
207
+ cy="32"
208
+ r="30"
209
+ fill="none"
210
+ stroke="currentColor"
211
+ strokeWidth="2"
212
+ strokeDasharray="188.4"
213
+ strokeDashoffset={progressOffset}
214
+ strokeLinecap="round"
215
+ className="text-primary transition-all duration-500"
216
+ />
217
+ </svg>
218
+ <span className="absolute inset-0 flex items-center justify-center text-xs font-medium">
219
+ {Math.round(progress)}
220
+ </span>
221
+ </div>
222
+ )}
223
+
224
+ {/* Badge */}
225
+ {badge && (
226
+ <div className="absolute -top-3 right-4 z-20">
227
+ <div className={cn(
228
+ "text-xs px-2.5 py-1 rounded-full font-semibold shadow-md",
229
+ badgeVariant === "default" && "bg-background text-foreground border border-border",
230
+ badgeVariant === "primary" && "bg-primary text-primary-foreground",
231
+ badgeVariant === "secondary" && "bg-secondary text-secondary-foreground",
232
+ badgeVariant === "success" && "bg-green-500 text-white",
233
+ badgeVariant === "warning" && "bg-amber-500 text-white",
234
+ badgeVariant === "danger" && "bg-red-500 text-white",
235
+ badgeVariant === "info" && "bg-blue-500 text-white"
236
+ )}>
237
+ {badge}
238
+ </div>
239
+ </div>
240
+ )}
241
+
242
+ {/* Loading spinner */}
243
+ {loading && (
244
+ <div className="absolute top-1/2 right-4 -translate-y-1/2 z-10">
245
+ <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
246
+ </div>
247
+ )}
248
+
249
+ <CollapsiblePrimitive.Root
250
+ ref={ref}
251
+ open={isOpen}
252
+ onOpenChange={handleOpenChange}
253
+ disabled={disabled || loading}
254
+ className={cn(
255
+ "w-full",
256
+ animationMode === "spring" && "[&_[data-state=open]]:animate-[collapsible-down_0.3s_cubic-bezier(0.34,1.56,0.64,1)]",
257
+ animationMode === "bounce" && "[&_[data-state=open]]:animate-[collapsible-down_0.4s_cubic-bezier(0.68,-0.55,0.265,1.55)]",
258
+ animationMode === "fade" && "[&_[data-state=open]]:animate-[collapsible-down_0.2s_ease-in-out]",
259
+ animationMode === "slide" && "[&_[data-state=open]]:animate-[slide-down_0.3s_ease-out]"
260
+ )}
261
+ >
262
+ {/* Provide context for children */}
263
+ <CollapsibleContext.Provider value={{
264
+ variant,
265
+ size,
266
+ animationMode,
267
+ lazy: lazy && !hasBeenOpened,
268
+ shortcut
269
+ }}>
270
+ {children}
271
+ </CollapsibleContext.Provider>
272
+ </CollapsiblePrimitive.Root>
273
+ </div>
274
+ );
275
+ });
276
+
277
+ MoonUICollapsiblePro.displayName = "MoonUICollapsiblePro"
278
+
279
+ // Context definition
280
+ const CollapsibleContext = React.createContext<{
281
+ variant?: CollapsibleVariant;
282
+ size?: CollapsibleSize;
283
+ animationMode?: AnimationMode;
284
+ lazy?: boolean;
285
+ shortcut?: string;
286
+ }>({});
287
+
288
+ // Enhanced Trigger component with variants
289
+ const collapsibleTriggerVariants = cva(
290
+ "flex w-full items-center gap-3 transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
21
291
  {
22
292
  variants: {
23
293
  variant: {
24
294
  default: "text-foreground hover:text-primary",
25
- ghost: "text-foreground hover:bg-accent/10 rounded",
26
- outline: "text-foreground border border-border rounded-t-md hover:bg-accent/5",
295
+ bordered: "text-foreground hover:text-primary hover:bg-primary/5 rounded-t-lg",
296
+ elevated: "text-foreground hover:text-primary hover:bg-primary/5 rounded-t-lg",
297
+ gradient: "text-foreground hover:text-primary",
298
+ glassmorphism: "text-foreground hover:text-primary hover:bg-white/10",
299
+ card: "text-foreground hover:text-primary hover:bg-accent/5 rounded-t-lg"
27
300
  },
28
301
  size: {
29
- sm: "text-xs py-2 px-3",
30
- default: "text-sm py-3 px-4",
31
- md: "text-base py-4 px-4",
32
- lg: "text-lg py-5 px-5",
302
+ xs: "text-xs py-2 px-3 min-h-[2.5rem]",
303
+ sm: "text-sm py-2.5 px-3.5 min-h-[3rem]",
304
+ md: "text-base py-3 px-4 min-h-[3.5rem]",
305
+ lg: "text-lg py-4 px-5 min-h-[4rem]",
306
+ xl: "text-xl py-5 px-6 min-h-[4.5rem]"
33
307
  },
34
308
  },
35
309
  defaultVariants: {
36
310
  variant: "default",
37
- size: "default",
311
+ size: "md",
38
312
  },
39
313
  }
40
314
  )
41
315
 
42
- interface CollapsibleTriggerProps
316
+ interface MoonUICollapsibleTriggerProProps
43
317
  extends React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Trigger>,
44
- VariantProps<typeof MoonUIcollapsibleTriggerVariantsPro> {}
318
+ VariantProps<typeof collapsibleTriggerVariants> {
319
+ /** Icon to show on the left */
320
+ leftIcon?: React.ReactNode;
321
+ /** Icon to show on the right (excluding chevron) */
322
+ rightIcon?: React.ReactNode;
323
+ /** Subtitle / description */
324
+ description?: string;
325
+ /** External link indicator */
326
+ external?: boolean;
327
+ /** Custom chevron icon */
328
+ customChevron?: React.ReactNode;
329
+ /** Hide chevron */
330
+ hideChevron?: boolean;
331
+ /** Status indicator */
332
+ status?: "success" | "warning" | "error" | "info";
333
+ }
45
334
 
46
335
  const MoonUICollapsibleTriggerPro = React.forwardRef<
47
336
  React.ElementRef<typeof CollapsiblePrimitive.Trigger>,
48
- CollapsibleTriggerProps
49
- >(({ className, children, variant, size, asChild, ...props }, ref) => {
50
- // asChild kullanıldığında otomatik ikon eklemeyi atla
337
+ MoonUICollapsibleTriggerProProps
338
+ >(({
339
+ className,
340
+ children,
341
+ variant: triggerVariant,
342
+ size: triggerSize,
343
+ asChild,
344
+ leftIcon,
345
+ rightIcon,
346
+ description,
347
+ external,
348
+ customChevron,
349
+ hideChevron,
350
+ status,
351
+ ...props
352
+ }, ref) => {
353
+ const { variant, size, shortcut } = React.useContext(CollapsibleContext);
354
+ const finalVariant = triggerVariant || variant || "default";
355
+ const finalSize = triggerSize || size || "md";
356
+
357
+ // Status icon mapping
358
+ const statusIcon = status && {
359
+ success: <CheckCircle2 className="h-4 w-4 text-green-500" />,
360
+ warning: <AlertCircle className="h-4 w-4 text-amber-500" />,
361
+ error: <XCircle className="h-4 w-4 text-red-500" />,
362
+ info: <Info className="h-4 w-4 text-blue-500" />
363
+ }[status];
364
+
365
+ // If asChild, render minimal wrapper
51
366
  if (asChild) {
52
367
  return (
53
368
  <CollapsiblePrimitive.Trigger
54
369
  ref={ref}
55
- className={cn(MoonUIcollapsibleTriggerVariantsPro({ variant, size }), className)}
370
+ className={cn(collapsibleTriggerVariants({ variant: finalVariant, size: finalSize }), className)}
56
371
  asChild={asChild}
57
372
  {...props}
58
373
  >
@@ -64,72 +379,253 @@ const MoonUICollapsibleTriggerPro = React.forwardRef<
64
379
  return (
65
380
  <CollapsiblePrimitive.Trigger
66
381
  ref={ref}
67
- className={cn(MoonUIcollapsibleTriggerVariantsPro({ variant, size }), className)}
382
+ className={cn(
383
+ collapsibleTriggerVariants({ variant: finalVariant, size: finalSize }),
384
+ "[&[data-state=open]>.chevron]:rotate-180",
385
+ "[&[data-state=open]]:text-primary",
386
+ className
387
+ )}
68
388
  {...props}
69
389
  >
70
- {children}
71
- <ChevronDown className="h-4 w-4 shrink-0 ml-auto transition-transform duration-200 [&[data-state=open]]:rotate-180" />
390
+ {/* Left icon */}
391
+ {leftIcon && (
392
+ <span className="text-muted-foreground">{leftIcon}</span>
393
+ )}
394
+
395
+ {/* Status icon */}
396
+ {statusIcon && !leftIcon && statusIcon}
397
+
398
+ {/* Main content */}
399
+ <div className="flex-1 text-left">
400
+ <div className="flex items-center gap-2">
401
+ {/* Main title */}
402
+ <span className="font-medium">{children}</span>
403
+
404
+ {/* External link indicator */}
405
+ {external && (
406
+ <ExternalLink className="h-3 w-3 text-muted-foreground" />
407
+ )}
408
+ </div>
409
+
410
+ {/* Description */}
411
+ {description && (
412
+ <div className="text-sm text-muted-foreground mt-1">
413
+ {description}
414
+ </div>
415
+ )}
416
+ </div>
417
+
418
+ {/* Right side elements */}
419
+ <div className="flex items-center gap-2">
420
+ {/* Keyboard shortcut */}
421
+ {shortcut && (
422
+ <kbd className="hidden sm:inline-flex h-6 px-2 items-center rounded border bg-muted text-xs font-medium text-muted-foreground">
423
+ {shortcut}
424
+ </kbd>
425
+ )}
426
+
427
+ {/* Right icon */}
428
+ {rightIcon && (
429
+ <span className="text-muted-foreground">{rightIcon}</span>
430
+ )}
431
+
432
+ {/* Chevron */}
433
+ {!hideChevron && (
434
+ <span className="chevron transition-transform duration-200 text-muted-foreground">
435
+ {customChevron || <ChevronDown className="h-4 w-4" />}
436
+ </span>
437
+ )}
438
+ </div>
72
439
  </CollapsiblePrimitive.Trigger>
73
440
  )
74
441
  })
75
- MoonUICollapsibleTriggerPro.displayName = CollapsiblePrimitive.Trigger.displayName
442
+ MoonUICollapsibleTriggerPro.displayName = "MoonUICollapsibleTriggerPro"
76
443
 
77
- const MoonUIcollapsibleContentVariantsPro = cva(
78
- "overflow-hidden transition-all data-[state=closed]:animate-collapse-up data-[state=open]:animate-collapse-down",
444
+ // Enhanced Content component with animations
445
+ const collapsibleContentVariants = cva(
446
+ "overflow-hidden transition-all",
79
447
  {
80
448
  variants: {
81
449
  variant: {
82
450
  default: "text-muted-foreground",
83
- ghost: "text-muted-foreground rounded-b",
84
- outline: "text-muted-foreground border border-t-0 border-border rounded-b-md",
451
+ bordered: "text-muted-foreground border-x border-b border-border rounded-b-lg",
452
+ elevated: "text-muted-foreground bg-muted/20",
453
+ gradient: "text-muted-foreground",
454
+ glassmorphism: "text-muted-foreground bg-white/5",
455
+ card: "text-muted-foreground border-x border-b border-border rounded-b-lg bg-card/50"
85
456
  },
86
457
  size: {
87
- sm: "text-xs",
88
- default: "text-sm",
458
+ xs: "text-xs",
459
+ sm: "text-sm",
89
460
  md: "text-base",
90
461
  lg: "text-lg",
462
+ xl: "text-xl"
91
463
  },
92
464
  },
93
465
  defaultVariants: {
94
466
  variant: "default",
95
- size: "default",
467
+ size: "md",
96
468
  },
97
469
  }
98
470
  )
99
471
 
100
- interface CollapsibleContentProps
472
+ interface MoonUICollapsibleContentProProps
101
473
  extends React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Content>,
102
- VariantProps<typeof MoonUIcollapsibleContentVariantsPro> {}
474
+ VariantProps<typeof collapsibleContentVariants> {
475
+ /** Content loading state */
476
+ contentLoading?: boolean;
477
+ /** Dynamic content loading function */
478
+ loadContent?: () => Promise<React.ReactNode>;
479
+ /** Remove padding */
480
+ noPadding?: boolean;
481
+ /** Custom padding */
482
+ padding?: string;
483
+ }
103
484
 
104
485
  const MoonUICollapsibleContentPro = React.forwardRef<
105
486
  React.ElementRef<typeof CollapsiblePrimitive.Content>,
106
- CollapsibleContentProps
107
- >(({ className, children, variant, size, ...props }, ref) => (
108
- <CollapsiblePrimitive.Content
109
- ref={ref}
110
- className={cn(MoonUIcollapsibleContentVariantsPro({ variant, size }), className)}
111
- {...props}
112
- >
113
- <div className="p-4">{children}</div>
114
- </CollapsiblePrimitive.Content>
115
- ))
116
- MoonUICollapsibleContentPro.displayName = CollapsiblePrimitive.Content.displayName
487
+ MoonUICollapsibleContentProProps
488
+ >(({
489
+ className,
490
+ children,
491
+ variant: contentVariant,
492
+ size: contentSize,
493
+ contentLoading,
494
+ loadContent,
495
+ noPadding,
496
+ padding,
497
+ ...props
498
+ }, ref) => {
499
+ const { variant, size, animationMode, lazy } = React.useContext(CollapsibleContext);
500
+ const finalVariant = contentVariant || variant || "default";
501
+ const finalSize = contentSize || size || "md";
502
+
503
+ const [dynamicContent, setDynamicContent] = React.useState<React.ReactNode>(null);
504
+ const [isLoading, setIsLoading] = React.useState(false);
505
+
506
+ // Dynamic content loading
507
+ React.useEffect(() => {
508
+ if (loadContent && !dynamicContent) {
509
+ setIsLoading(true);
510
+ loadContent()
511
+ .then(setDynamicContent)
512
+ .finally(() => setIsLoading(false));
513
+ }
514
+ }, [loadContent, dynamicContent]);
117
515
 
516
+ // Determine padding based on size
517
+ const defaultPadding = !noPadding && {
518
+ xs: "p-3",
519
+ sm: "p-3.5",
520
+ md: "p-4",
521
+ lg: "p-5",
522
+ xl: "p-6"
523
+ }[finalSize];
524
+
525
+ return (
526
+ <CollapsiblePrimitive.Content
527
+ ref={ref}
528
+ className={cn(
529
+ collapsibleContentVariants({ variant: finalVariant, size: finalSize }),
530
+ // Animation modes
531
+ animationMode === "spring" && "data-[state=closed]:animate-[collapsible-up_0.3s_cubic-bezier(0.34,1.56,0.64,1)] data-[state=open]:animate-[collapsible-down_0.3s_cubic-bezier(0.34,1.56,0.64,1)]",
532
+ animationMode === "bounce" && "data-[state=closed]:animate-[collapsible-up_0.4s_cubic-bezier(0.68,-0.55,0.265,1.55)] data-[state=open]:animate-[collapsible-down_0.4s_cubic-bezier(0.68,-0.55,0.265,1.55)]",
533
+ animationMode === "fade" && "data-[state=closed]:animate-[collapsible-up_0.2s_ease-in-out] data-[state=open]:animate-[collapsible-down_0.2s_ease-in-out]",
534
+ animationMode === "slide" && "data-[state=closed]:animate-[slide-up_0.3s_ease-out] data-[state=open]:animate-[slide-down_0.3s_ease-out]",
535
+ animationMode === "smooth" && "data-[state=closed]:animate-collapse-up data-[state=open]:animate-collapse-down",
536
+ className
537
+ )}
538
+ {...props}
539
+ >
540
+ <div className={cn(padding || defaultPadding)}>
541
+ {lazy ? (
542
+ <div className="flex items-center gap-2 py-4">
543
+ <Clock className="h-4 w-4 animate-pulse" />
544
+ <span className="text-sm">Click to load content...</span>
545
+ </div>
546
+ ) : (contentLoading || isLoading) ? (
547
+ <div className="flex items-center gap-2 py-4">
548
+ <Loader2 className="h-4 w-4 animate-spin" />
549
+ <span className="text-sm">Loading content...</span>
550
+ </div>
551
+ ) : (
552
+ dynamicContent || children
553
+ )}
554
+ </div>
555
+ </CollapsiblePrimitive.Content>
556
+ )
557
+ })
558
+ MoonUICollapsibleContentPro.displayName = "MoonUICollapsibleContentPro"
559
+
560
+ // Utility Hooks
561
+ export const useCollapsibleAnalytics = () => {
562
+ const [analytics, setAnalytics] = React.useState<{
563
+ openCount: number;
564
+ lastOpened: Date | null;
565
+ totalTimeOpen: number;
566
+ }>({
567
+ openCount: 0,
568
+ lastOpened: null,
569
+ totalTimeOpen: 0
570
+ });
571
+
572
+ const trackOpen = React.useCallback(() => {
573
+ setAnalytics(prev => ({
574
+ ...prev,
575
+ openCount: prev.openCount + 1,
576
+ lastOpened: new Date()
577
+ }));
578
+ }, []);
579
+
580
+ const trackClose = React.useCallback(() => {
581
+ setAnalytics(prev => {
582
+ if (prev.lastOpened) {
583
+ const timeOpen = Date.now() - prev.lastOpened.getTime();
584
+ return {
585
+ ...prev,
586
+ totalTimeOpen: prev.totalTimeOpen + timeOpen,
587
+ lastOpened: null
588
+ };
589
+ }
590
+ return prev;
591
+ });
592
+ }, []);
593
+
594
+ return { analytics, trackOpen, trackClose };
595
+ };
118
596
 
119
597
  // Internal aliases for Pro component usage
120
598
  export const CollapsibleInternal = MoonUICollapsiblePro
121
- export const collapsibleTriggerVariantsInternal = MoonUIcollapsibleTriggerVariantsPro
599
+ export const collapsibleTriggerVariantsInternal = collapsibleTriggerVariants
122
600
  export const CollapsibleTriggerInternal = MoonUICollapsibleTriggerPro
123
- export const collapsibleContentVariantsInternal = MoonUIcollapsibleContentVariantsPro
601
+ export const collapsibleContentVariantsInternal = collapsibleContentVariants
124
602
  export const CollapsibleContentInternal = MoonUICollapsibleContentPro
125
603
 
126
604
  // Pro exports
127
- export { MoonUICollapsiblePro, MoonUIcollapsibleTriggerVariantsPro, MoonUICollapsibleTriggerPro, MoonUIcollapsibleContentVariantsPro, MoonUICollapsibleContentPro }
605
+ export {
606
+ MoonUICollapsiblePro,
607
+ collapsibleTriggerVariants as MoonUIcollapsibleTriggerVariantsPro,
608
+ MoonUICollapsibleTriggerPro,
609
+ collapsibleContentVariants as MoonUIcollapsibleContentVariantsPro,
610
+ MoonUICollapsibleContentPro
611
+ }
128
612
 
129
613
  // Clean exports (without MoonUI prefix for easier usage)
130
- export { MoonUICollapsiblePro as Collapsible, MoonUIcollapsibleTriggerVariantsPro as collapsibleTriggerVariants, MoonUICollapsibleTriggerPro as CollapsibleTrigger, MoonUIcollapsibleContentVariantsPro as collapsibleContentVariants, MoonUICollapsibleContentPro as CollapsibleContent }
614
+ export {
615
+ MoonUICollapsiblePro as Collapsible,
616
+ collapsibleTriggerVariants,
617
+ MoonUICollapsibleTriggerPro as CollapsibleTrigger,
618
+ collapsibleContentVariants,
619
+ MoonUICollapsibleContentPro as CollapsibleContent
620
+ }
131
621
 
622
+ // Type exports
132
623
  export type {
133
- CollapsibleTriggerProps,
134
- CollapsibleContentProps
624
+ MoonUICollapsibleProProps,
625
+ MoonUICollapsibleTriggerProProps,
626
+ MoonUICollapsibleContentProProps,
627
+ CollapsibleSize,
628
+ CollapsibleVariant,
629
+ AnimationMode,
630
+ BadgeVariant
135
631
  }