@moontra/moonui 2.0.8 → 2.0.9

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 (94) hide show
  1. package/package.json +9 -2
  2. package/src/__tests__/use-intersection-observer.test.tsx +216 -0
  3. package/src/__tests__/use-local-storage.test.tsx +174 -0
  4. package/src/__tests__/use-pro-access.test.tsx +183 -0
  5. package/src/components/ui/__tests__/accordion.test.tsx +571 -0
  6. package/src/components/ui/__tests__/alert.test.tsx +484 -0
  7. package/src/components/ui/__tests__/aspect-ratio.test.tsx +492 -0
  8. package/src/components/ui/__tests__/avatar.test.tsx +382 -0
  9. package/src/components/ui/__tests__/badge.test.tsx +364 -0
  10. package/src/components/ui/__tests__/breadcrumb.test.tsx +687 -0
  11. package/src/components/ui/__tests__/button.test.tsx +91 -0
  12. package/src/components/ui/__tests__/card.test.tsx +104 -0
  13. package/src/components/ui/__tests__/checkbox.test.tsx +591 -0
  14. package/src/components/ui/__tests__/collapsible.test.tsx +592 -0
  15. package/src/components/ui/__tests__/color-picker.test.tsx +365 -0
  16. package/src/components/ui/__tests__/command.test.tsx +677 -0
  17. package/src/components/ui/__tests__/data-table.test.tsx +256 -0
  18. package/src/components/ui/__tests__/date-picker.test.tsx +320 -0
  19. package/src/components/ui/__tests__/dialog.test.tsx +764 -0
  20. package/src/components/ui/__tests__/input.test.tsx +318 -0
  21. package/src/components/ui/__tests__/label.test.tsx +103 -0
  22. package/src/components/ui/__tests__/popover.test.tsx +637 -0
  23. package/src/components/ui/__tests__/progress.test.tsx +382 -0
  24. package/src/components/ui/__tests__/radio-group.test.tsx +555 -0
  25. package/src/components/ui/__tests__/select.test.tsx +705 -0
  26. package/src/components/ui/__tests__/skeleton.test.tsx +253 -0
  27. package/src/components/ui/__tests__/slider.test.tsx +493 -0
  28. package/src/components/ui/__tests__/switch.test.tsx +372 -0
  29. package/src/components/ui/__tests__/table.test.tsx +824 -0
  30. package/src/components/ui/__tests__/tabs.test.tsx +887 -0
  31. package/src/components/ui/__tests__/toast.test.tsx +458 -0
  32. package/src/components/ui/__tests__/tooltip.test.tsx +583 -0
  33. package/src/components/ui/accordion.tsx +63 -0
  34. package/src/components/ui/alert.tsx +130 -0
  35. package/src/components/ui/aspect-ratio.tsx +72 -0
  36. package/src/components/ui/avatar.tsx +135 -0
  37. package/src/components/ui/badge.tsx +225 -0
  38. package/src/components/ui/breadcrumb.tsx +207 -0
  39. package/src/components/ui/button.stories.tsx +162 -0
  40. package/src/components/ui/button.tsx +221 -0
  41. package/src/components/ui/calendar.tsx +262 -0
  42. package/src/components/ui/card.stories.tsx +208 -0
  43. package/src/components/ui/card.tsx +141 -0
  44. package/src/components/ui/checkbox.tsx +256 -0
  45. package/src/components/ui/collapsible.tsx +129 -0
  46. package/src/components/ui/color-picker.tsx +664 -0
  47. package/src/components/ui/command.tsx +218 -0
  48. package/src/components/ui/data-table.stories.tsx +509 -0
  49. package/src/components/ui/data-table.tsx +623 -0
  50. package/src/components/ui/date-picker.stories.tsx +321 -0
  51. package/src/components/ui/date-picker.tsx +603 -0
  52. package/src/components/ui/dialog.tsx +332 -0
  53. package/src/components/ui/dropdown-menu.tsx +200 -0
  54. package/src/components/ui/file-upload.tsx +400 -0
  55. package/src/components/ui/github-stars.tsx +201 -0
  56. package/src/components/ui/index.ts +12 -0
  57. package/src/components/ui/input.stories.tsx +255 -0
  58. package/src/components/ui/input.tsx +219 -0
  59. package/src/components/ui/label.tsx +26 -0
  60. package/src/components/ui/locked-component.tsx +215 -0
  61. package/src/components/ui/moon-logo.tsx +97 -0
  62. package/src/components/ui/pagination.tsx +116 -0
  63. package/src/components/ui/popover.tsx +183 -0
  64. package/src/components/ui/progress.tsx +182 -0
  65. package/src/components/ui/radio-group.tsx +243 -0
  66. package/src/components/ui/select.tsx +273 -0
  67. package/src/components/ui/separator.tsx +140 -0
  68. package/src/components/ui/simple-editor.tsx +652 -0
  69. package/src/components/ui/skeleton.tsx +351 -0
  70. package/src/components/ui/slider.tsx +351 -0
  71. package/src/components/ui/switch.tsx +83 -0
  72. package/src/components/ui/table.tsx +322 -0
  73. package/src/components/ui/tabs.tsx +195 -0
  74. package/src/components/ui/textarea.tsx +46 -0
  75. package/src/components/ui/toast.tsx +313 -0
  76. package/src/components/ui/toggle.tsx +47 -0
  77. package/src/components/ui/tooltip.tsx +152 -0
  78. package/src/docs/theme-system.md +1194 -0
  79. package/src/index.tsx +39 -0
  80. package/src/lib/micro-interactions.ts +255 -0
  81. package/src/lib/theme.tsx +398 -0
  82. package/src/lib/utils.ts +69 -0
  83. package/src/styles/design-system.css +365 -0
  84. package/src/styles/index.css +4 -0
  85. package/src/styles/tailwind.css +6 -0
  86. package/src/styles/tokens.css +453 -0
  87. package/src/use-intersection-observer.tsx +154 -0
  88. package/src/use-local-storage.tsx +71 -0
  89. package/src/use-paddle.ts +138 -0
  90. package/src/use-performance-optimizer.ts +379 -0
  91. package/src/use-pro-access.ts +141 -0
  92. package/src/use-scroll-animation.ts +221 -0
  93. package/src/use-subscription.ts +37 -0
  94. package/src/use-toast.ts +32 -0
@@ -0,0 +1,130 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { cva, type VariantProps } from "class-variance-authority";
5
+ import { AlertCircle, AlertTriangle, Info, Check, X } from "lucide-react";
6
+
7
+ import { cn } from "../../lib/utils";
8
+
9
+ /**
10
+ * Alert Component
11
+ *
12
+ * Yüksek kaliteli, özelleştirilebilir ve erişilebilir alert bileşeni.
13
+ * Bildirim, uyarı ve dikkat çekmek gereken içerikler için kullanılır.
14
+ */
15
+
16
+ const alertVariants = cva(
17
+ "relative w-full flex items-center gap-3 p-4 border text-foreground [&>svg]:shrink-0",
18
+ {
19
+ variants: {
20
+ variant: {
21
+ default: "bg-background text-foreground border-border",
22
+ primary: "bg-primary/10 text-primary border-primary/30",
23
+ success: "bg-success/10 text-success border-success/30",
24
+ warning: "bg-warning/10 text-warning border-warning/30",
25
+ error: "bg-destructive/10 text-destructive border-destructive/30",
26
+ info: "bg-blue-500/10 text-blue-500 border-blue-500/30",
27
+ },
28
+ size: {
29
+ sm: "py-2 text-xs",
30
+ default: "py-3 text-sm",
31
+ lg: "py-4 text-base",
32
+ },
33
+ radius: {
34
+ none: "rounded-none",
35
+ sm: "rounded-sm",
36
+ default: "rounded-md",
37
+ lg: "rounded-lg",
38
+ full: "rounded-full",
39
+ },
40
+ withClose: {
41
+ true: "pr-10",
42
+ },
43
+ },
44
+ defaultVariants: {
45
+ variant: "default",
46
+ size: "default",
47
+ radius: "default",
48
+ withClose: false,
49
+ },
50
+ }
51
+ );
52
+
53
+ export interface AlertProps
54
+ extends React.HTMLAttributes<HTMLDivElement>,
55
+ VariantProps<typeof alertVariants> {
56
+ /** Alert ikonunu gizler */
57
+ hideIcon?: boolean;
58
+ /** Kapatma butonu ekler */
59
+ closable?: boolean;
60
+ /** Kapatma butonu tıklandığında çalışacak fonksiyon */
61
+ onClose?: () => void;
62
+ }
63
+
64
+ const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
65
+ ({ className, variant = "default", size, radius, hideIcon = false, closable = false, onClose, children, ...props }, ref) => {
66
+ // Alert türüne göre ikon belirleme
67
+ const Icon = React.useMemo(() => {
68
+ switch (variant) {
69
+ case "success":
70
+ return Check;
71
+ case "warning":
72
+ return AlertTriangle;
73
+ case "error":
74
+ return AlertCircle;
75
+ case "info":
76
+ return Info;
77
+ default:
78
+ return Info;
79
+ }
80
+ }, [variant]);
81
+
82
+ return (
83
+ <div
84
+ ref={ref}
85
+ role="alert"
86
+ className={cn(alertVariants({ variant, size, radius, withClose: closable }), className)}
87
+ {...props}
88
+ >
89
+ {!hideIcon && <Icon className="h-5 w-5" />}
90
+ <div className="flex-1">{children}</div>
91
+ {closable && onClose && (
92
+ <button
93
+ onClick={onClose}
94
+ className="absolute right-3 top-3 inline-flex h-6 w-6 items-center justify-center rounded-full opacity-70 transition-opacity hover:opacity-100"
95
+ aria-label="Kapat"
96
+ >
97
+ <X className="h-4 w-4" />
98
+ </button>
99
+ )}
100
+ </div>
101
+ );
102
+ }
103
+ );
104
+ Alert.displayName = "Alert";
105
+
106
+ const AlertTitle = React.forwardRef<
107
+ HTMLParagraphElement,
108
+ React.HTMLAttributes<HTMLHeadingElement>
109
+ >(({ className, ...props }, ref) => (
110
+ <h5
111
+ ref={ref}
112
+ className={cn("font-semibold leading-tight tracking-tight mb-1", className)}
113
+ {...props}
114
+ />
115
+ ));
116
+ AlertTitle.displayName = "AlertTitle";
117
+
118
+ const AlertDescription = React.forwardRef<
119
+ HTMLParagraphElement,
120
+ React.HTMLAttributes<HTMLParagraphElement>
121
+ >(({ className, ...props }, ref) => (
122
+ <div
123
+ ref={ref}
124
+ className={cn("text-sm leading-5 text-muted-foreground", className)}
125
+ {...props}
126
+ />
127
+ ));
128
+ AlertDescription.displayName = "AlertDescription";
129
+
130
+ export { Alert, AlertTitle, AlertDescription };
@@ -0,0 +1,72 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+
6
+ import { cn } from "../../lib/utils"
7
+
8
+ /**
9
+ * Aspect Ratio Component
10
+ *
11
+ * A component that maintains a specific aspect ratio for content.
12
+ * Particularly useful for images, videos, and media content in responsive designs.
13
+ * Fully integrated with the theme system, accessible and customizable.
14
+ */
15
+
16
+ const aspectRatioVariants = cva(
17
+ "relative overflow-hidden",
18
+ {
19
+ variants: {
20
+ variant: {
21
+ default: "rounded-md bg-muted/10",
22
+ ghost: "bg-transparent",
23
+ outline: "rounded-md border border-border",
24
+ card: "rounded-md bg-card shadow-sm",
25
+ },
26
+ radius: {
27
+ none: "rounded-none",
28
+ sm: "rounded-sm",
29
+ md: "rounded-md",
30
+ lg: "rounded-lg",
31
+ full: "rounded-full",
32
+ },
33
+ },
34
+ defaultVariants: {
35
+ variant: "default",
36
+ },
37
+ }
38
+ )
39
+
40
+ interface AspectRatioProps
41
+ extends React.HTMLAttributes<HTMLDivElement>,
42
+ VariantProps<typeof aspectRatioVariants> {
43
+ /**
44
+ * Aspect ratio (width/height). For example 16/9, 4/3, 1/1 etc.
45
+ * @default 16/9
46
+ */
47
+ ratio?: number
48
+ }
49
+
50
+ const AspectRatio = React.forwardRef<
51
+ HTMLDivElement,
52
+ AspectRatioProps
53
+ >(({ className, variant, radius, ratio = 16 / 9, style, children, ...props }, ref) => (
54
+ <div
55
+ ref={ref}
56
+ className={cn(aspectRatioVariants({ variant, radius }), className)}
57
+ style={{
58
+ position: "relative",
59
+ paddingBottom: `${(1 / ratio) * 100}%`,
60
+ ...style
61
+ }}
62
+ {...props}
63
+ >
64
+ <div className="absolute inset-0">
65
+ {children}
66
+ </div>
67
+ </div>
68
+ ))
69
+ AspectRatio.displayName = "AspectRatio"
70
+
71
+ export { AspectRatio, aspectRatioVariants }
72
+ export type { AspectRatioProps }
@@ -0,0 +1,135 @@
1
+ import * as React from "react";
2
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ const avatarVariants = cva(
8
+ "relative flex shrink-0 overflow-hidden",
9
+ {
10
+ variants: {
11
+ size: {
12
+ default: "h-10 w-10",
13
+ xs: "h-6 w-6",
14
+ sm: "h-8 w-8",
15
+ md: "h-10 w-10",
16
+ lg: "h-12 w-12",
17
+ xl: "h-16 w-16",
18
+ "2xl": "h-20 w-20",
19
+ },
20
+ radius: {
21
+ default: "rounded-full",
22
+ sm: "rounded-md",
23
+ lg: "rounded-xl",
24
+ full: "rounded-full",
25
+ none: "rounded-none",
26
+ },
27
+ variant: {
28
+ default: "",
29
+ ring: "ring-2 ring-gray-300 dark:ring-gray-600",
30
+ ringOffset: "ring-2 ring-gray-300 dark:ring-gray-600 ring-offset-2 ring-offset-background dark:ring-offset-gray-950",
31
+ border: "border-2 border-gray-200 dark:border-gray-800"
32
+ }
33
+ },
34
+ defaultVariants: {
35
+ size: "default",
36
+ radius: "default",
37
+ variant: "default"
38
+ },
39
+ }
40
+ );
41
+
42
+ export interface AvatarProps
43
+ extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>,
44
+ VariantProps<typeof avatarVariants> {}
45
+
46
+ const Avatar = React.forwardRef<
47
+ React.ElementRef<typeof AvatarPrimitive.Root>,
48
+ AvatarProps
49
+ >(({ className, size, radius, variant, ...props }, ref) => (
50
+ <AvatarPrimitive.Root
51
+ ref={ref}
52
+ className={cn(avatarVariants({ size, radius, variant }), className)}
53
+ {...props}
54
+ />
55
+ ));
56
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
57
+
58
+ const AvatarImage = React.forwardRef<
59
+ React.ElementRef<typeof AvatarPrimitive.Image>,
60
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
61
+ >(({ className, ...props }, ref) => (
62
+ <AvatarPrimitive.Image
63
+ ref={ref}
64
+ className={cn("aspect-square h-full w-full", className)}
65
+ {...props}
66
+ />
67
+ ));
68
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
69
+
70
+ const AvatarFallback = React.forwardRef<
71
+ React.ElementRef<typeof AvatarPrimitive.Fallback>,
72
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
73
+ >(({ className, ...props }, ref) => (
74
+ <AvatarPrimitive.Fallback
75
+ ref={ref}
76
+ className={cn(
77
+ "flex h-full w-full items-center justify-center bg-muted",
78
+ className
79
+ )}
80
+ {...props}
81
+ />
82
+ ));
83
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
84
+
85
+ // Avatar Group Component for displaying multiple avatars
86
+ interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
87
+ limit?: number;
88
+ avatars: React.ReactNode[];
89
+ overlapOffset?: number;
90
+ }
91
+
92
+ const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(
93
+ ({ className, limit, avatars, overlapOffset = -8, ...props }, ref) => {
94
+ const visibleAvatars = limit ? avatars.slice(0, limit) : avatars;
95
+ const remainingCount = limit ? Math.max(0, avatars.length - limit) : 0;
96
+
97
+ return (
98
+ <div
99
+ ref={ref}
100
+ className={cn("flex items-center", className)}
101
+ {...props}
102
+ >
103
+ <div className="flex">
104
+ {visibleAvatars.map((avatar, index) => (
105
+ <div
106
+ key={index}
107
+ className="relative"
108
+ style={{
109
+ marginLeft: index === 0 ? 0 : `${overlapOffset}px`,
110
+ zIndex: visibleAvatars.length - index
111
+ }}
112
+ >
113
+ {avatar}
114
+ </div>
115
+ ))}
116
+ {remainingCount > 0 && (
117
+ <div
118
+ className="relative z-0"
119
+ style={{ marginLeft: `${overlapOffset}px` }}
120
+ >
121
+ <Avatar variant="border">
122
+ <AvatarFallback>
123
+ +{remainingCount}
124
+ </AvatarFallback>
125
+ </Avatar>
126
+ </div>
127
+ )}
128
+ </div>
129
+ </div>
130
+ );
131
+ }
132
+ );
133
+ AvatarGroup.displayName = "AvatarGroup";
134
+
135
+ export { Avatar, AvatarImage, AvatarFallback, AvatarGroup };
@@ -0,0 +1,225 @@
1
+ import * as React from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "../../lib/utils";
4
+
5
+ /**
6
+ * Premium Badge Component
7
+ *
8
+ * Durum, kategori ve etiketleme için yüksek kaliteli badge bileşeni.
9
+ * Dark ve light modda uyumlu, erişilebilir ve çeşitli varyantlar sunar.
10
+ */
11
+
12
+ const badgeVariants = cva(
13
+ ["inline-flex items-center gap-1.5",
14
+ "font-medium transition-colors duration-200",
15
+ "border focus:outline-none",
16
+ "focus-visible:ring-2 focus-visible:ring-offset-1"],
17
+ {
18
+ variants: {
19
+ variant: {
20
+ primary: [
21
+ "border-transparent bg-primary text-primary-foreground",
22
+ "hover:bg-primary-hover dark:hover:bg-primary/90",
23
+ "focus-visible:ring-primary/30 dark:focus-visible:ring-primary/40",
24
+ "dark:bg-primary/90 dark:text-white dark:shadow-inner dark:shadow-primary/10",
25
+ ],
26
+ secondary: [
27
+ "border-transparent bg-secondary text-secondary-foreground",
28
+ "hover:bg-gray-200 dark:hover:bg-gray-700/90",
29
+ "focus-visible:ring-gray-400/30 dark:focus-visible:ring-gray-500/40",
30
+ "dark:bg-gray-800 dark:text-gray-100 dark:shadow-inner dark:shadow-gray-950/10",
31
+ ],
32
+ outline: [
33
+ "border-gray-200 dark:border-gray-700",
34
+ "bg-transparent text-foreground",
35
+ "hover:border-gray-300 dark:hover:border-gray-600",
36
+ "focus-visible:ring-gray-400/30 dark:focus-visible:ring-gray-500/40",
37
+ "dark:text-gray-200 dark:bg-transparent dark:backdrop-blur-sm",
38
+ ],
39
+ destructive: [
40
+ "border-transparent bg-error text-white",
41
+ "hover:bg-error/90 dark:hover:bg-error/80",
42
+ "focus-visible:ring-error/30 dark:focus-visible:ring-error/25",
43
+ "dark:bg-error/90 dark:text-white dark:shadow-inner dark:shadow-error/10",
44
+ ],
45
+ success: [
46
+ "border-transparent bg-success text-white",
47
+ "hover:bg-success/90 dark:hover:bg-success/80",
48
+ "focus-visible:ring-success/30 dark:focus-visible:ring-success/25",
49
+ "dark:bg-success/90 dark:text-white dark:shadow-inner dark:shadow-success/10",
50
+ ],
51
+ warning: [
52
+ "border-transparent bg-warning text-white",
53
+ "hover:bg-warning/90 dark:hover:bg-warning/80",
54
+ "focus-visible:ring-warning/30 dark:focus-visible:ring-warning/25",
55
+ "dark:bg-warning/90 dark:text-gray-900 dark:shadow-inner dark:shadow-warning/10",
56
+ ],
57
+ ghost: [
58
+ "border-transparent bg-transparent text-foreground",
59
+ "hover:bg-gray-100 dark:hover:bg-gray-800/80",
60
+ "focus-visible:ring-gray-400/30 dark:focus-visible:ring-gray-500/40",
61
+ "dark:text-gray-200 dark:backdrop-blur-sm",
62
+ "transition-colors duration-200",
63
+ ],
64
+ pro: [
65
+ "border-transparent bg-gradient-to-r from-purple-600 to-pink-600 text-white",
66
+ "hover:from-purple-700 hover:to-pink-700",
67
+ "focus-visible:ring-purple-400/30 dark:focus-visible:ring-purple-500/40",
68
+ "shadow-md dark:shadow-lg dark:shadow-purple-500/10",
69
+ ],
70
+ admin: [
71
+ "border-transparent bg-gradient-to-r from-purple-600 to-pink-600 text-white",
72
+ "hover:from-purple-700 hover:to-pink-700",
73
+ "focus-visible:ring-purple-400/30 dark:focus-visible:ring-purple-500/40",
74
+ "shadow-md dark:shadow-lg dark:shadow-purple-500/10",
75
+ ],
76
+ },
77
+ size: {
78
+ sm: "h-5 px-2 text-xs",
79
+ md: "h-6 px-3 text-sm",
80
+ lg: "h-8 px-4 text-base",
81
+ },
82
+ radius: {
83
+ default: "rounded-full",
84
+ sm: "rounded-md",
85
+ lg: "rounded-xl",
86
+ none: "rounded-none",
87
+ }
88
+ },
89
+ defaultVariants: {
90
+ variant: "primary",
91
+ size: "md",
92
+ radius: "default",
93
+ },
94
+ }
95
+ );
96
+
97
+ export interface BadgeProps
98
+ extends React.HTMLAttributes<HTMLDivElement>,
99
+ Omit<VariantProps<typeof badgeVariants>, 'variant'> {
100
+ withDot?: boolean;
101
+ dotColor?: string;
102
+ removable?: boolean;
103
+ onRemove?: () => void;
104
+ leftIcon?: React.ReactNode;
105
+ rightIcon?: React.ReactNode;
106
+ variant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'success' | 'warning' | 'ghost' | 'pro' | 'admin';
107
+ }
108
+
109
+ /**
110
+ * Premium Badge Component
111
+ *
112
+ * @param props - Badge bileşeni özellikleri
113
+ * @param props.variant - Badgenin görsel varyantı
114
+ * @param props.size - Badge boyutu
115
+ * @param props.radius - Köşe yuvarlama stili
116
+ * @param props.withDot - Başında nokta gösterimi
117
+ * @param props.dotColor - Noktanın rengi (özel)
118
+ * @param props.removable - Kaldırılabilir badge (X simgesi ile)
119
+ * @param props.onRemove - Kaldırma işlevi
120
+ * @param props.leftIcon - Badge'in solunda görüntülenecek ikon
121
+ * @param props.rightIcon - Badge'in sağında görüntülenecek ikon
122
+ */
123
+ function Badge({
124
+ className,
125
+ variant,
126
+ size,
127
+ radius,
128
+ withDot,
129
+ dotColor,
130
+ removable,
131
+ onRemove,
132
+ leftIcon,
133
+ rightIcon,
134
+ children,
135
+ ...props
136
+ }: BadgeProps) {
137
+ // Auto-assign icons and content for special variants
138
+ let autoLeftIcon = leftIcon;
139
+ let autoChildren = children;
140
+
141
+ if (variant === 'pro') {
142
+ // Auto Sparkles icon for pro
143
+ autoLeftIcon = leftIcon || (
144
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-3 h-3">
145
+ <path d="M12 0L13.09 8.26L22 9L13.09 9.74L12 18L10.91 9.74L2 9L10.91 8.26L12 0Z" fill="currentColor"/>
146
+ <path d="M19 5L19.5 7L21 7.5L19.5 8L19 10L18.5 8L17 7.5L18.5 7L19 5Z" fill="currentColor"/>
147
+ <path d="M19 15L19.5 17L21 17.5L19.5 18L19 20L18.5 18L17 17.5L18.5 17L19 15Z" fill="currentColor"/>
148
+ </svg>
149
+ );
150
+ autoChildren = children || 'Pro';
151
+ }
152
+
153
+ if (variant === 'admin') {
154
+ // Auto CheckCircle icon for admin
155
+ autoLeftIcon = leftIcon || (
156
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-3 h-3">
157
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" fill="currentColor"/>
158
+ </svg>
159
+ );
160
+ autoChildren = children || 'Admin Pro';
161
+ }
162
+
163
+ return (
164
+ <div
165
+ className={cn(badgeVariants({ variant, size, radius }), className)}
166
+ data-removable={removable ? "" : undefined}
167
+ {...props}
168
+ >
169
+ {withDot && (
170
+ <span
171
+ className={cn(
172
+ "h-2 w-2 rounded-full",
173
+ dotColor ||
174
+ (variant === "destructive" ? "bg-white" :
175
+ variant === "success" ? "bg-white" :
176
+ variant === "warning" ? "bg-white" :
177
+ variant === "secondary" ? "bg-secondary-foreground" :
178
+ variant === "outline" ? "bg-foreground" :
179
+ variant === "ghost" ? "bg-foreground" :
180
+ variant === "pro" ? "bg-white" :
181
+ variant === "admin" ? "bg-white" :
182
+ "bg-primary-foreground")
183
+ )}
184
+ aria-hidden="true"
185
+ />
186
+ )}
187
+ {autoLeftIcon && (
188
+ <span className="inline-flex shrink-0">
189
+ {autoLeftIcon}
190
+ </span>
191
+ )}
192
+ <span className="truncate">{autoChildren}</span>
193
+ {rightIcon && (
194
+ <span className="inline-flex shrink-0">
195
+ {rightIcon}
196
+ </span>
197
+ )}
198
+ {removable && onRemove && (
199
+ <button
200
+ type="button"
201
+ className="ml-1 -mr-1 h-3.5 w-3.5 rounded-full inline-flex items-center justify-center hover:bg-black/10 dark:hover:bg-white/10"
202
+ onClick={(e) => {
203
+ e.stopPropagation();
204
+ onRemove();
205
+ }}
206
+ aria-label="Remove badge"
207
+ >
208
+ <svg
209
+ width="8"
210
+ height="8"
211
+ viewBox="0 0 8 8"
212
+ fill="none"
213
+ xmlns="http://www.w3.org/2000/svg"
214
+ className="opacity-70"
215
+ aria-hidden="true"
216
+ >
217
+ <path d="M0.799988 7.19999L7.19999 0.799988M0.799988 0.799988L7.19999 7.19999" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
218
+ </svg>
219
+ </button>
220
+ )}
221
+ </div>
222
+ );
223
+ }
224
+
225
+ export { Badge, badgeVariants };