@moontra/moonui-pro 2.18.6 → 2.19.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moontra/moonui-pro",
3
- "version": "2.18.6",
3
+ "version": "2.19.0",
4
4
  "description": "Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -9,8 +9,8 @@ import { Card, CardContent } from "../ui/card"
9
9
  import { Button } from "../ui/button"
10
10
  import { useSubscription } from "../../hooks/use-subscription"
11
11
 
12
- const animatedButtonVariants = cva(
13
- "relative inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 overflow-hidden",
12
+ const moonUIAnimatedButtonProVariants = cva(
13
+ "relative inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 overflow-hidden min-w-fit",
14
14
  {
15
15
  variants: {
16
16
  variant: {
@@ -20,68 +20,143 @@ const animatedButtonVariants = cva(
20
20
  secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
21
21
  ghost: "hover:bg-accent hover:text-accent-foreground",
22
22
  link: "text-primary underline-offset-4 hover:underline",
23
+ gradient: "bg-gradient-to-r from-purple-600 to-pink-600 text-white hover:from-purple-700 hover:to-pink-700",
24
+ glow: "bg-primary text-primary-foreground shadow-lg hover:shadow-xl hover:shadow-primary/25",
23
25
  },
24
26
  size: {
25
27
  default: "h-9 px-4 py-2",
26
28
  sm: "h-8 rounded-md px-3 text-xs",
27
29
  lg: "h-10 rounded-md px-8",
28
- },
30
+ xl: "h-11 rounded-md px-6 text-base font-medium",
31
+ icon: "h-9 w-9",
32
+ }
29
33
  },
30
34
  defaultVariants: {
31
35
  variant: "default",
32
- size: "default",
36
+ size: "default"
33
37
  },
34
38
  }
35
39
  )
36
40
 
37
- interface AnimatedButtonProps
41
+ interface MoonUIAnimatedButtonProProps
38
42
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
39
- VariantProps<typeof animatedButtonVariants> {
43
+ VariantProps<typeof moonUIAnimatedButtonProVariants> {
40
44
  state?: "idle" | "loading" | "success" | "error"
41
45
  onStateChange?: (state: "idle" | "loading" | "success" | "error") => void
46
+ loadingText?: string
47
+ successText?: string
48
+ errorText?: string
49
+ ripple?: boolean
50
+ iconRotate?: boolean
51
+ shimmerSpeed?: "slow" | "normal" | "fast"
52
+ glowIntensity?: "low" | "medium" | "high"
53
+ showProgressBar?: boolean
54
+ autoResetDelay?: number
55
+ animation?: "none" | "bounce" | "pulse" | "shimmer" | "slide" | "scale" | "rotate" | "shake"
42
56
  }
43
57
 
44
- const AnimatedButtonInternal = React.forwardRef<HTMLButtonElement, AnimatedButtonProps>(
45
- ({ className, variant, size, state = "idle", onStateChange, children, onClick, ...props }, ref) => {
58
+ const MoonUIAnimatedButtonProInternal = React.forwardRef<HTMLButtonElement, MoonUIAnimatedButtonProProps>(
59
+ ({
60
+ className,
61
+ variant,
62
+ size,
63
+ animation = "none",
64
+ state = "idle",
65
+ onStateChange,
66
+ children,
67
+ onClick,
68
+ loadingText = "Loading...",
69
+ successText = "Success!",
70
+ errorText = "Error!",
71
+ ripple = false,
72
+ iconRotate = false,
73
+ shimmerSpeed = "normal",
74
+ glowIntensity = "medium",
75
+ showProgressBar = false,
76
+ autoResetDelay = 2000,
77
+ onDrag,
78
+ onDragEnd,
79
+ onDragStart,
80
+ onAnimationStart,
81
+ onAnimationEnd,
82
+ ...props
83
+ }, ref) => {
46
84
  const [internalState, setInternalState] = useState<"idle" | "loading" | "success" | "error">("idle")
85
+ const [ripples, setRipples] = useState<Array<{x: number, y: number, id: number}>>([])
86
+ const [progress, setProgress] = useState(0)
87
+ const [isHovered, setIsHovered] = useState(false)
47
88
  const currentState = state !== "idle" ? state : internalState
48
89
 
49
90
  const handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
50
91
  if (currentState === "loading") return
51
92
 
93
+ // Ripple effect
94
+ if (ripple) {
95
+ const rect = e.currentTarget.getBoundingClientRect()
96
+ const x = e.clientX - rect.left
97
+ const y = e.clientY - rect.top
98
+ const id = Date.now()
99
+
100
+ setRipples([...ripples, { x, y, id }])
101
+ setTimeout(() => {
102
+ setRipples(prev => prev.filter(r => r.id !== id))
103
+ }, 600)
104
+ }
105
+
52
106
  setInternalState("loading")
53
107
  onStateChange?.("loading")
108
+ setProgress(0)
109
+
110
+ // Simulate progress
111
+ if (showProgressBar) {
112
+ const progressInterval = setInterval(() => {
113
+ setProgress(prev => {
114
+ if (prev >= 90) {
115
+ clearInterval(progressInterval)
116
+ return 90
117
+ }
118
+ return prev + 10
119
+ })
120
+ }, 200)
121
+ }
54
122
 
55
123
  if (onClick) {
56
124
  try {
57
125
  await onClick(e)
126
+ setProgress(100)
58
127
  setInternalState("success")
59
128
  onStateChange?.("success")
60
129
 
61
130
  setTimeout(() => {
62
131
  setInternalState("idle")
63
132
  onStateChange?.("idle")
64
- }, 2000)
133
+ setProgress(0)
134
+ }, autoResetDelay)
65
135
  } catch (error) {
136
+ setProgress(0)
66
137
  setInternalState("error")
67
138
  onStateChange?.("error")
68
139
 
69
140
  setTimeout(() => {
70
141
  setInternalState("idle")
71
142
  onStateChange?.("idle")
72
- }, 2000)
143
+ }, autoResetDelay)
73
144
  }
74
145
  }
75
146
  }
76
147
 
77
148
  const getIcon = () => {
149
+ const iconClass = cn("h-4 w-4", {
150
+ "animate-spin": currentState === "loading" || (iconRotate && currentState !== "idle"),
151
+ })
152
+
78
153
  switch (currentState) {
79
154
  case "loading":
80
- return <Loader2 className="h-4 w-4 animate-spin" />
155
+ return <Loader2 className={iconClass} />
81
156
  case "success":
82
- return <Check className="h-4 w-4" />
157
+ return <Check className={cn(iconClass, "animate-scale-in")} />
83
158
  case "error":
84
- return <X className="h-4 w-4" />
159
+ return <X className={cn(iconClass, "animate-shake")} />
85
160
  default:
86
161
  return null
87
162
  }
@@ -98,42 +173,140 @@ const AnimatedButtonInternal = React.forwardRef<HTMLButtonElement, AnimatedButto
98
173
  }
99
174
  }
100
175
 
176
+ const getShimmerSpeed = () => {
177
+ switch (shimmerSpeed) {
178
+ case "slow":
179
+ return "duration-1500"
180
+ case "fast":
181
+ return "duration-500"
182
+ default:
183
+ return "duration-1000"
184
+ }
185
+ }
186
+
187
+ const getGlowIntensity = () => {
188
+ switch (glowIntensity) {
189
+ case "low":
190
+ return "shadow-lg"
191
+ case "high":
192
+ return "shadow-2xl"
193
+ default:
194
+ return "shadow-xl"
195
+ }
196
+ }
197
+
198
+
199
+ // whileHover direkt olarak kullanılacak
200
+ let whileHoverAnimation: any = undefined
201
+ let whileTapAnimation: any = undefined
202
+
203
+ // Animation specific hover states
204
+ if (animation === "bounce") {
205
+ whileHoverAnimation = {
206
+ y: [0, -10, 0],
207
+ transition: {
208
+ duration: 0.6,
209
+ repeat: Infinity,
210
+ repeatType: "loop"
211
+ }
212
+ }
213
+ } else if (animation === "pulse") {
214
+ whileHoverAnimation = {
215
+ scale: [1, 1.1, 1],
216
+ transition: {
217
+ duration: 1,
218
+ repeat: Infinity,
219
+ repeatType: "loop"
220
+ }
221
+ }
222
+ } else if (animation === "shake") {
223
+ // Shake için CSS animation kullanacağız
224
+ whileHoverAnimation = undefined
225
+ } else if (animation === "rotate") {
226
+ whileHoverAnimation = {
227
+ rotate: 10,
228
+ transition: { type: "spring", stiffness: 300 }
229
+ }
230
+ } else if (animation === "scale") {
231
+ whileHoverAnimation = { scale: 1.05 }
232
+ whileTapAnimation = { scale: 0.95 }
233
+ } else if (animation === "slide") {
234
+ whileHoverAnimation = { y: -4 }
235
+ }
236
+
101
237
  return (
102
- <button
103
- className={cn(animatedButtonVariants({ variant, size }), className)}
238
+ <motion.button
239
+ {...props}
240
+ className={cn(
241
+ moonUIAnimatedButtonProVariants({ variant, size }),
242
+ variant === "glow" && getGlowIntensity(),
243
+ animation === "shake" && isHovered && "animate-shake",
244
+ className
245
+ )}
104
246
  ref={ref}
105
247
  onClick={handleClick}
106
248
  disabled={currentState === "loading" || props.disabled}
107
- {...props}
249
+ onMouseEnter={() => setIsHovered(true)}
250
+ onMouseLeave={() => setIsHovered(false)}
251
+ whileHover={whileHoverAnimation}
252
+ whileTap={whileTapAnimation}
108
253
  >
109
- <motion.div
110
- className="flex items-center gap-2"
111
- animate={{
112
- width: currentState !== "idle" ? "auto" : "100%"
113
- }}
114
- transition={{ duration: 0.2 }}
115
- >
254
+ {/* Progress Bar */}
255
+ {showProgressBar && currentState === "loading" && (
116
256
  <motion.div
117
- animate={{
118
- scale: currentState !== "idle" ? 1 : 0,
119
- width: currentState !== "idle" ? "auto" : 0
120
- }}
121
- transition={{ duration: 0.2 }}
122
- className="flex items-center"
123
- >
124
- {getIcon()}
125
- </motion.div>
126
-
127
- <motion.span
128
- animate={{
129
- opacity: currentState === "idle" ? 1 : 0,
130
- x: currentState !== "idle" ? -20 : 0
257
+ className="absolute bottom-0 left-0 h-1 bg-primary-foreground/20 rounded-full"
258
+ initial={{ width: 0 }}
259
+ animate={{ width: `${progress}%` }}
260
+ transition={{ duration: 0.3 }}
261
+ />
262
+ )}
263
+
264
+ {/* Shimmer Effect */}
265
+ {animation === "shimmer" && (
266
+ <motion.div
267
+ className="absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent"
268
+ initial={{ x: "-100%" }}
269
+ animate={{ x: "100%" }}
270
+ transition={{
271
+ duration: shimmerSpeed === "slow" ? 1.5 : shimmerSpeed === "fast" ? 0.5 : 1,
272
+ repeat: Infinity,
273
+ repeatDelay: 1
131
274
  }}
132
- transition={{ duration: 0.2 }}
133
- >
134
- {children}
135
- </motion.span>
136
- </motion.div>
275
+ />
276
+ )}
277
+
278
+ {/* Content */}
279
+ <div className="relative flex items-center justify-center gap-2 z-10">
280
+ {/* Icon variant için özel düzenleme */}
281
+ {size === "icon" ? (
282
+ // Icon size için sadece icon göster
283
+ currentState === "idle" ? (
284
+ children
285
+ ) : (
286
+ getIcon()
287
+ )
288
+ ) : (
289
+ // Diğer boyutlar için normal akış
290
+ <>
291
+ {currentState === "idle" ? (
292
+ <>
293
+ {React.isValidElement(children) && React.cloneElement(children as React.ReactElement)}
294
+ {typeof children === 'string' && children}
295
+ {React.isValidElement(children) || typeof children === 'string' ? null : children}
296
+ </>
297
+ ) : (
298
+ <>
299
+ {getIcon()}
300
+ <span className="ml-2">
301
+ {currentState === "loading" && loadingText}
302
+ {currentState === "success" && successText}
303
+ {currentState === "error" && errorText}
304
+ </span>
305
+ </>
306
+ )}
307
+ </>
308
+ )}
309
+ </div>
137
310
 
138
311
  {/* Background animation */}
139
312
  <motion.div
@@ -144,27 +317,41 @@ const AnimatedButtonInternal = React.forwardRef<HTMLButtonElement, AnimatedButto
144
317
  initial={{ scale: 0, opacity: 0 }}
145
318
  animate={{
146
319
  scale: currentState === "success" || currentState === "error" ? 1 : 0,
147
- opacity: currentState === "success" || currentState === "error" ? 1 : 0
320
+ opacity: currentState === "success" || currentState === "error" ? 0.2 : 0
148
321
  }}
149
322
  transition={{ duration: 0.3 }}
150
- style={{ zIndex: -1 }}
323
+ style={{ zIndex: 0 }}
151
324
  />
152
- </button>
325
+
326
+ {/* Ripple Effect */}
327
+ {ripples.map(ripple => (
328
+ <span
329
+ key={ripple.id}
330
+ className="absolute bg-primary/20 rounded-full animate-ripple pointer-events-none"
331
+ style={{
332
+ left: ripple.x - 10,
333
+ top: ripple.y - 10,
334
+ width: 20,
335
+ height: 20,
336
+ }}
337
+ />
338
+ ))}
339
+ </motion.button>
153
340
  )
154
341
  }
155
342
  )
156
343
 
157
- AnimatedButtonInternal.displayName = "AnimatedButtonInternal"
344
+ MoonUIAnimatedButtonProInternal.displayName = "MoonUIAnimatedButtonProInternal"
158
345
 
159
- export const AnimatedButton = React.forwardRef<HTMLButtonElement, AnimatedButtonProps>(
160
- ({ className, ...props }, ref) => {
346
+ export const MoonUIAnimatedButtonPro = React.forwardRef<HTMLButtonElement, MoonUIAnimatedButtonProProps>(
347
+ (props, ref) => {
161
348
  // Pro package - always show component
162
349
  const { hasProAccess, isLoading } = useSubscription()
163
350
 
164
351
  // Show upgrade prompt if no pro access
165
352
  if (!isLoading && !hasProAccess) {
166
353
  return (
167
- <Card className={cn("w-fit", className)}>
354
+ <Card className={cn("w-fit", props.className)}>
168
355
  <CardContent className="py-6 text-center">
169
356
  <div className="space-y-4">
170
357
  <div className="rounded-full bg-purple-100 dark:bg-purple-900/30 p-3 w-fit mx-auto">
@@ -188,11 +375,11 @@ export const AnimatedButton = React.forwardRef<HTMLButtonElement, AnimatedButton
188
375
  )
189
376
  }
190
377
 
191
- return <AnimatedButtonInternal className={className} ref={ref} {...props} />
378
+ return <MoonUIAnimatedButtonProInternal {...props} ref={ref} />
192
379
  }
193
380
  )
194
381
 
195
- AnimatedButton.displayName = "AnimatedButton"
382
+ MoonUIAnimatedButtonPro.displayName = "MoonUIAnimatedButtonPro"
196
383
 
197
- export { animatedButtonVariants }
198
- export type { AnimatedButtonProps }
384
+ export { moonUIAnimatedButtonProVariants }
385
+ export type { MoonUIAnimatedButtonProProps }
@@ -4,7 +4,11 @@
4
4
  export * from "./ui"
5
5
 
6
6
  // Animated Button
7
- export * from "./animated-button"
7
+ export {
8
+ MoonUIAnimatedButtonPro,
9
+ moonUIAnimatedButtonProVariants,
10
+ type MoonUIAnimatedButtonProProps
11
+ } from "./animated-button"
8
12
 
9
13
  // Error Boundary
10
14
  export * from "./error-boundary"