@moontra/moonui-pro 2.18.6 → 2.20.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 (49) hide show
  1. package/dist/index.d.ts +3251 -0
  2. package/dist/index.mjs +2704 -1479
  3. package/package.json +137 -136
  4. package/src/__tests__/use-local-storage.test.tsx +2 -2
  5. package/src/components/advanced-chart/index.tsx +6 -6
  6. package/src/components/animated-button/index.tsx +240 -53
  7. package/src/components/calendar/event-dialog.tsx +1 -1
  8. package/src/components/calendar/index.tsx +1 -1
  9. package/src/components/calendar-pro/index.tsx +2 -4
  10. package/src/components/dashboard/demo.tsx +2 -2
  11. package/src/components/dashboard/widgets/activity-feed.tsx +1 -1
  12. package/src/components/dashboard/widgets/metric-card.tsx +1 -1
  13. package/src/components/enhanced/button.tsx +13 -13
  14. package/src/components/file-upload/file-upload.test.tsx +20 -19
  15. package/src/components/form-wizard/form-wizard-progress.tsx +7 -7
  16. package/src/components/gesture-drawer/index.tsx +551 -0
  17. package/src/components/github-stars/hooks.ts +1 -1
  18. package/src/components/github-stars/index.tsx +1 -1
  19. package/src/components/github-stars/types.ts +1 -0
  20. package/src/components/health-check/index.tsx +2 -2
  21. package/src/components/hover-card-3d/index.tsx +437 -74
  22. package/src/components/index.ts +15 -2
  23. package/src/components/lazy-component/index.tsx +4 -2
  24. package/src/components/license-error/index.tsx +29 -0
  25. package/src/components/memory-efficient-data/index.tsx +1 -1
  26. package/src/components/pinch-zoom/index.tsx +438 -42
  27. package/src/components/rich-text-editor/index.tsx +12 -12
  28. package/src/components/timeline/index.tsx +2 -2
  29. package/src/components/ui/aspect-ratio.tsx +186 -22
  30. package/src/components/ui/button.tsx +47 -50
  31. package/src/components/ui/card.tsx +98 -30
  32. package/src/components/ui/gesture-drawer.tsx +11 -0
  33. package/src/components/ui/index.ts +18 -1
  34. package/src/components/ui/lightbox.tsx +606 -0
  35. package/src/components/ui/media-gallery.tsx +612 -0
  36. package/src/components/ui/select.tsx +134 -35
  37. package/src/components/ui/toggle.tsx +78 -15
  38. package/src/components/virtual-list/index.tsx +7 -7
  39. package/src/index.ts +4 -4
  40. package/src/lib/component-metadata.ts +18 -0
  41. package/src/lib/paddle.ts +17 -0
  42. package/src/patterns/login-form/index.tsx +1 -1
  43. package/src/patterns/login-form/types.ts +6 -6
  44. package/src/styles/index.css +14 -4
  45. package/src/types/next-auth.d.ts +21 -0
  46. package/src/use-local-storage.tsx +3 -3
  47. package/src/use-scroll-animation.ts +3 -5
  48. package/src/components/ui/animated-button.tsx +0 -185
  49. package/src/components/ui/hover-card-3d.tsx +0 -103
@@ -1,125 +1,488 @@
1
1
  "use client"
2
2
 
3
- import React, { useRef, useState } from "react"
3
+ import React, { useRef, useState, useCallback, useEffect, useMemo } from "react"
4
4
  import { motion, useMotionValue, useSpring, useTransform } from "framer-motion"
5
5
  import { cn } from "../../lib/utils"
6
6
  import { Card, CardContent } from "../ui/card"
7
7
  import { Button } from "../ui/button"
8
8
  import { Lock, Sparkles } from "lucide-react"
9
9
  import { useSubscription } from "../../hooks/use-subscription"
10
+ import { cva, type VariantProps } from "class-variance-authority"
10
11
 
11
- export interface HoverCard3DProps extends React.HTMLAttributes<HTMLDivElement> {
12
+ const hoverCard3DVariants = cva(
13
+ "relative rounded-lg border bg-card text-card-foreground shadow-sm transition-all duration-200",
14
+ {
15
+ variants: {
16
+ variant: {
17
+ subtle: "hover:bg-card/95",
18
+ dramatic: "hover:bg-gradient-to-br hover:from-card hover:to-card/80",
19
+ gaming: "hover:border-primary/50 hover:shadow-lg hover:shadow-primary/25",
20
+ elegant: "hover:border-border/50 hover:bg-gradient-to-br hover:from-card hover:via-card/95 hover:to-card/90",
21
+ neon: "hover:border-primary hover:shadow-[0_0_30px_rgba(var(--primary),0.3)]"
22
+ },
23
+ shadowIntensity: {
24
+ none: "",
25
+ light: "hover:shadow-md",
26
+ medium: "hover:shadow-lg",
27
+ heavy: "hover:shadow-xl",
28
+ extreme: "hover:shadow-2xl"
29
+ },
30
+ glowEffect: {
31
+ none: "",
32
+ subtle: "",
33
+ vibrant: "",
34
+ neon: ""
35
+ }
36
+ },
37
+ defaultVariants: {
38
+ variant: "subtle",
39
+ shadowIntensity: "medium",
40
+ glowEffect: "none"
41
+ }
42
+ }
43
+ )
44
+
45
+ export interface SpringConfig {
46
+ stiffness?: number
47
+ damping?: number
48
+ mass?: number
49
+ velocity?: number
50
+ restSpeed?: number
51
+ restDelta?: number
52
+ }
53
+
54
+ export type OverlayRenderProp = (props: {
55
+ isHovered: boolean
56
+ rotateX: number
57
+ rotateY: number
58
+ }) => React.ReactNode
59
+
60
+ export interface HoverCard3DProps
61
+ extends React.HTMLAttributes<HTMLDivElement>,
62
+ VariantProps<typeof hoverCard3DVariants> {
63
+ /**
64
+ * The perspective value for 3D transformation
65
+ * @default 1000
66
+ */
12
67
  perspective?: number
68
+
69
+ /**
70
+ * Maximum rotation angle in degrees
71
+ * @default 15
72
+ */
73
+ maxRotation?: number
74
+
75
+ /**
76
+ * @deprecated Use maxRotation instead
77
+ */
13
78
  rotationIntensity?: number
14
- springConfig?: {
15
- stiffness?: number
16
- damping?: number
79
+
80
+ /**
81
+ * Scale factor when hovered
82
+ * @default 1.05
83
+ */
84
+ scale?: number
85
+
86
+ /**
87
+ * Spring animation configuration
88
+ */
89
+ springConfig?: SpringConfig
90
+
91
+ /**
92
+ * Animation speed multiplier (0-1)
93
+ * @default 1
94
+ */
95
+ animationSpeed?: number
96
+
97
+ /**
98
+ * Static or dynamic overlay content
99
+ */
100
+ overlay?: React.ReactNode | OverlayRenderProp
101
+
102
+ /**
103
+ * Show overlay even when not hovered
104
+ * @default false
105
+ */
106
+ overlayAlwaysVisible?: boolean
107
+
108
+ /**
109
+ * Glow color (CSS color value)
110
+ */
111
+ glowColor?: string
112
+
113
+ /**
114
+ * Glow blur amount in pixels
115
+ * @default 20
116
+ */
117
+ glowBlur?: number
118
+
119
+ /**
120
+ * Glow spread amount
121
+ * @default 1.2
122
+ */
123
+ glowSpread?: number
124
+
125
+ /**
126
+ * Enable touch support for mobile devices
127
+ * @default true
128
+ */
129
+ enableTouch?: boolean
130
+
131
+ /**
132
+ * Enable keyboard navigation
133
+ * @default true
134
+ */
135
+ enableKeyboard?: boolean
136
+
137
+ /**
138
+ * Callback when hover starts
139
+ */
140
+ onHoverStart?: () => void
141
+
142
+ /**
143
+ * Callback when hover ends
144
+ */
145
+ onHoverEnd?: () => void
146
+
147
+ /**
148
+ * Callback when rotation changes
149
+ */
150
+ onRotationChange?: (rotateX: number, rotateY: number) => void
151
+
152
+ /**
153
+ * Animation delay in ms
154
+ * @default 0
155
+ */
156
+ animationDelay?: number
157
+
158
+ /**
159
+ * ARIA label for accessibility
160
+ */
161
+ ariaLabel?: string
162
+
163
+ /**
164
+ * Auto focus on mount
165
+ * @default false
166
+ */
167
+ autoFocus?: boolean
168
+
169
+ /**
170
+ * Control which axes can rotate
171
+ * @default { x: true, y: true }
172
+ */
173
+ rotateAxes?: {
174
+ x?: boolean
175
+ y?: boolean
17
176
  }
18
177
  }
19
178
 
20
179
  const HoverCard3DInternal = React.forwardRef<HTMLDivElement, HoverCard3DProps>(
21
180
  ({
22
181
  children,
23
- className,
182
+ className,
183
+ variant,
184
+ shadowIntensity,
185
+ glowEffect,
24
186
  perspective = 1000,
25
- rotationIntensity = 15,
26
- springConfig = { stiffness: 200, damping: 15 },
27
- ...props
187
+ maxRotation = 15,
188
+ rotationIntensity,
189
+ scale = 1.05,
190
+ springConfig = {
191
+ stiffness: 200,
192
+ damping: 15,
193
+ mass: 1,
194
+ velocity: 0
195
+ },
196
+ animationSpeed = 1,
197
+ overlay,
198
+ overlayAlwaysVisible = false,
199
+ glowColor = "rgb(var(--primary))",
200
+ glowBlur = 20,
201
+ glowSpread = 1.2,
202
+ enableTouch = true,
203
+ enableKeyboard = true,
204
+ onHoverStart,
205
+ onHoverEnd,
206
+ onRotationChange,
207
+ animationDelay = 0,
208
+ ariaLabel,
209
+ autoFocus = false,
210
+ rotateAxes = { x: true, y: true },
211
+ ...restProps
28
212
  }, ref) => {
213
+ // Filter out drag and animation event handlers to avoid conflicts with Framer Motion
214
+ const { onDrag, onDragStart, onDragEnd, onDragOver, onDrop, onAnimationStart, onAnimationEnd, onAnimationIteration, ...props } = restProps
29
215
  const cardRef = useRef<HTMLDivElement>(null)
30
216
  const [isHovered, setIsHovered] = useState(false)
217
+ const [isFocused, setIsFocused] = useState(false)
218
+
219
+ // Use maxRotation, fallback to rotationIntensity for backwards compatibility
220
+ const rotation = maxRotation || rotationIntensity || 15
31
221
 
32
222
  const x = useMotionValue(0)
33
223
  const y = useMotionValue(0)
34
224
 
35
- const springX = useSpring(x, springConfig)
36
- const springY = useSpring(y, springConfig)
225
+ const springX = useSpring(x, {
226
+ ...springConfig,
227
+ stiffness: springConfig.stiffness! * animationSpeed,
228
+ damping: springConfig.damping! / animationSpeed
229
+ })
230
+ const springY = useSpring(y, {
231
+ ...springConfig,
232
+ stiffness: springConfig.stiffness! * animationSpeed,
233
+ damping: springConfig.damping! / animationSpeed
234
+ })
37
235
 
38
- const rotateX = useTransform(springY, [-0.5, 0.5], [rotationIntensity, -rotationIntensity])
39
- const rotateY = useTransform(springX, [-0.5, 0.5], [-rotationIntensity, rotationIntensity])
236
+ const rotateX = useTransform(
237
+ springY,
238
+ [-1, 1],
239
+ rotateAxes.x ? [rotation, -rotation] : [0, 0]
240
+ )
241
+ const rotateY = useTransform(
242
+ springX,
243
+ [-1, 1],
244
+ rotateAxes.y ? [-rotation, rotation] : [0, 0]
245
+ )
40
246
 
41
- const handleMouseMove = (e: React.MouseEvent) => {
247
+ const handleMouseMove = useCallback((e: React.MouseEvent | React.TouchEvent) => {
42
248
  if (!cardRef.current) return
43
249
 
44
250
  const rect = cardRef.current.getBoundingClientRect()
45
251
  const centerX = rect.left + rect.width / 2
46
252
  const centerY = rect.top + rect.height / 2
253
+
254
+ let clientX: number, clientY: number
255
+
256
+ if ('touches' in e && enableTouch) {
257
+ clientX = e.touches[0].clientX
258
+ clientY = e.touches[0].clientY
259
+ } else if ('clientX' in e) {
260
+ clientX = e.clientX
261
+ clientY = e.clientY
262
+ } else {
263
+ return
264
+ }
47
265
 
48
- const rotateXValue = (e.clientY - centerY) / (rect.height / 2)
49
- const rotateYValue = (e.clientX - centerX) / (rect.width / 2)
266
+ const rotateXValue = (clientY - centerY) / (rect.height / 2)
267
+ const rotateYValue = (clientX - centerX) / (rect.width / 2)
50
268
 
51
269
  x.set(rotateYValue)
52
270
  y.set(rotateXValue)
53
- }
271
+
272
+ if (onRotationChange) {
273
+ onRotationChange(rotateX.get(), rotateY.get())
274
+ }
275
+ }, [enableTouch, x, y, rotateX, rotateY, onRotationChange])
54
276
 
55
- const handleMouseEnter = () => {
277
+ const handleMouseEnter = useCallback(() => {
56
278
  setIsHovered(true)
57
- }
279
+ onHoverStart?.()
280
+ }, [onHoverStart])
58
281
 
59
- const handleMouseLeave = () => {
282
+ const handleMouseLeave = useCallback(() => {
60
283
  setIsHovered(false)
61
284
  x.set(0)
62
285
  y.set(0)
63
- }
286
+ onHoverEnd?.()
287
+ }, [x, y, onHoverEnd])
64
288
 
65
- return (
66
- <motion.div
67
- ref={(node) => {
68
- cardRef.current = node
69
- if (typeof ref === "function") {
70
- ref(node)
71
- } else if (ref) {
72
- ref.current = node
289
+ const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
290
+ if (!enableKeyboard || !isFocused) return
291
+
292
+ const step = 0.1
293
+ let newX = x.get()
294
+ let newY = y.get()
295
+
296
+ switch (e.key) {
297
+ case 'ArrowUp':
298
+ newY = Math.max(-0.5, newY - step)
299
+ y.set(newY)
300
+ e.preventDefault()
301
+ break
302
+ case 'ArrowDown':
303
+ newY = Math.min(0.5, newY + step)
304
+ y.set(newY)
305
+ e.preventDefault()
306
+ break
307
+ case 'ArrowLeft':
308
+ newX = Math.max(-0.5, newX - step)
309
+ x.set(newX)
310
+ e.preventDefault()
311
+ break
312
+ case 'ArrowRight':
313
+ newX = Math.min(0.5, newX + step)
314
+ x.set(newX)
315
+ e.preventDefault()
316
+ break
317
+ case 'Enter':
318
+ case ' ':
319
+ setIsHovered(!isHovered)
320
+ if (!isHovered) {
321
+ onHoverStart?.()
322
+ } else {
323
+ onHoverEnd?.()
73
324
  }
74
- }}
75
- className={cn(
76
- "relative rounded-lg border bg-card text-card-foreground shadow-sm transition-colors duration-200 hover:bg-card/90",
77
- className
78
- )}
79
- onMouseMove={handleMouseMove}
80
- onMouseEnter={handleMouseEnter}
81
- onMouseLeave={handleMouseLeave}
82
- style={{
83
- transformPerspective: perspective,
84
- transformStyle: "preserve-3d",
85
- }}
86
- animate={{
87
- rotateX: isHovered ? rotateX.get() : 0,
88
- rotateY: isHovered ? rotateY.get() : 0,
89
- scale: isHovered ? 1.05 : 1,
90
- }}
91
- transition={{ duration: 0.15 }}
92
- >
325
+ e.preventDefault()
326
+ break
327
+ case 'Escape':
328
+ x.set(0)
329
+ y.set(0)
330
+ setIsHovered(false)
331
+ onHoverEnd?.()
332
+ e.preventDefault()
333
+ break
334
+ }
335
+
336
+ if (onRotationChange) {
337
+ onRotationChange(rotateX.get(), rotateY.get())
338
+ }
339
+ }, [enableKeyboard, isFocused, x, y, isHovered, onHoverStart, onHoverEnd, rotateX, rotateY, onRotationChange])
340
+
341
+ useEffect(() => {
342
+ if (autoFocus && cardRef.current) {
343
+ cardRef.current.focus()
344
+ }
345
+ }, [autoFocus])
346
+
347
+ const overlayContent = useMemo(() => {
348
+ if (!overlay) return null
349
+
350
+ if (typeof overlay === 'function') {
351
+ return overlay({
352
+ isHovered,
353
+ rotateX: rotateX.get(),
354
+ rotateY: rotateY.get()
355
+ })
356
+ }
357
+
358
+ return overlay
359
+ }, [overlay, isHovered, rotateX, rotateY])
360
+
361
+ const glowStyle = useMemo(() => {
362
+ if (glowEffect === 'none') return {}
363
+
364
+ let opacity = 0
365
+ let blur = glowBlur
366
+ let spread = glowSpread
367
+
368
+ switch (glowEffect) {
369
+ case 'subtle':
370
+ opacity = isHovered ? 0.3 : 0
371
+ break
372
+ case 'vibrant':
373
+ opacity = isHovered ? 0.6 : 0
374
+ blur = glowBlur * 1.5
375
+ break
376
+ case 'neon':
377
+ opacity = isHovered ? 0.8 : 0
378
+ blur = glowBlur * 2
379
+ spread = glowSpread * 1.3
380
+ break
381
+ }
382
+
383
+ return {
384
+ opacity,
385
+ filter: `blur(${blur}px)`,
386
+ scale: spread,
387
+ backgroundColor: glowColor
388
+ }
389
+ }, [glowEffect, isHovered, glowBlur, glowSpread, glowColor])
390
+
391
+ return (
392
+ <div style={{ perspective: `${perspective}px` }}>
393
+ <motion.div
394
+ ref={(node) => {
395
+ cardRef.current = node
396
+ if (typeof ref === "function") {
397
+ ref(node)
398
+ } else if (ref) {
399
+ ref.current = node
400
+ }
401
+ }}
402
+ className={cn(
403
+ hoverCard3DVariants({ variant, shadowIntensity, glowEffect }),
404
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
405
+ className
406
+ )}
407
+ onMouseMove={handleMouseMove}
408
+ onMouseEnter={handleMouseEnter}
409
+ onMouseLeave={handleMouseLeave}
410
+ onTouchMove={enableTouch ? handleMouseMove : undefined}
411
+ onTouchStart={enableTouch ? handleMouseEnter : undefined}
412
+ onTouchEnd={enableTouch ? handleMouseLeave : undefined}
413
+ onKeyDown={handleKeyDown}
414
+ onFocus={() => setIsFocused(true)}
415
+ onBlur={() => setIsFocused(false)}
416
+ style={{
417
+ transformStyle: "preserve-3d",
418
+ transformOrigin: "center center",
419
+ rotateX: isHovered || isFocused ? rotateX : 0,
420
+ rotateY: isHovered || isFocused ? rotateY : 0,
421
+ scale: isHovered || isFocused ? scale : 1,
422
+ }}
423
+ transition={{
424
+ type: "spring",
425
+ stiffness: springConfig.stiffness,
426
+ damping: springConfig.damping,
427
+ duration: 0.15 * (1 / animationSpeed),
428
+ delay: animationDelay / 1000
429
+ }}
430
+ tabIndex={enableKeyboard ? 0 : undefined}
431
+ role={enableKeyboard ? "button" : undefined}
432
+ aria-label={ariaLabel}
433
+ {...props}
434
+ >
93
435
  <motion.div
94
436
  className="relative z-10"
95
437
  animate={{
96
- z: isHovered ? 20 : 0,
438
+ z: isHovered || isFocused ? 20 : 0,
97
439
  }}
98
- transition={{ duration: 0.2 }}
440
+ transition={{ duration: 0.2 * (1 / animationSpeed) }}
99
441
  >
100
442
  {children}
101
443
  </motion.div>
102
444
 
445
+ {/* Overlay */}
446
+ {overlayContent && (
447
+ <motion.div
448
+ className="absolute inset-0 rounded-lg pointer-events-none z-20"
449
+ animate={{
450
+ opacity: overlayAlwaysVisible ? 1 : (isHovered || isFocused ? 1 : 0),
451
+ }}
452
+ transition={{ duration: 0.3 * (1 / animationSpeed) }}
453
+ >
454
+ {overlayContent}
455
+ </motion.div>
456
+ )}
457
+
103
458
  {/* Gradient overlay */}
104
- <motion.div
105
- className="absolute inset-0 rounded-lg bg-gradient-to-br from-white/5 via-transparent to-black/5 pointer-events-none"
106
- animate={{
107
- opacity: isHovered ? 1 : 0,
108
- }}
109
- transition={{ duration: 0.3 }}
110
- />
459
+ {variant !== 'subtle' && (
460
+ <motion.div
461
+ className={cn(
462
+ "absolute inset-0 rounded-lg pointer-events-none",
463
+ variant === 'dramatic' && "bg-gradient-to-br from-white/10 via-transparent to-black/10",
464
+ variant === 'gaming' && "bg-gradient-to-br from-primary/10 via-transparent to-primary/5",
465
+ variant === 'elegant' && "bg-gradient-to-br from-white/5 via-transparent to-black/5",
466
+ variant === 'neon' && "bg-gradient-to-br from-primary/20 via-transparent to-primary/10"
467
+ )}
468
+ animate={{
469
+ opacity: isHovered || isFocused ? 1 : 0,
470
+ }}
471
+ transition={{ duration: 0.3 * (1 / animationSpeed) }}
472
+ />
473
+ )}
111
474
 
112
475
  {/* Glow effect */}
113
- <motion.div
114
- className="absolute inset-0 rounded-lg bg-primary/5 blur-xl"
115
- animate={{
116
- opacity: isHovered ? 0.8 : 0,
117
- scale: isHovered ? 1.2 : 1,
118
- }}
119
- transition={{ duration: 0.3 }}
120
- style={{ zIndex: -1 }}
121
- />
476
+ {glowEffect !== 'none' && (
477
+ <motion.div
478
+ className="absolute inset-0 rounded-lg pointer-events-none"
479
+ animate={glowStyle}
480
+ transition={{ duration: 0.3 * (1 / animationSpeed) }}
481
+ style={{ zIndex: -1 }}
482
+ />
483
+ )}
122
484
  </motion.div>
485
+ </div>
123
486
  )
124
487
  }
125
488
  )
@@ -127,16 +490,14 @@ const HoverCard3DInternal = React.forwardRef<HTMLDivElement, HoverCard3DProps>(
127
490
  HoverCard3DInternal.displayName = "HoverCard3DInternal"
128
491
 
129
492
  export const HoverCard3D = React.forwardRef<HTMLDivElement, HoverCard3DProps>(
130
- ({ className, ...props }, ref) => {
131
- // Check if we're in docs mode or have pro access
493
+ (props, ref) => {
494
+ // Pro package - always show component
132
495
  const { hasProAccess, isLoading } = useSubscription()
133
496
 
134
- // In docs mode, always show the component
135
-
136
- // If not in docs mode and no pro access, show upgrade prompt
497
+ // Show upgrade prompt if no pro access
137
498
  if (!isLoading && !hasProAccess) {
138
499
  return (
139
- <Card className={cn("w-fit", className)}>
500
+ <Card className={cn("w-fit", props.className)}>
140
501
  <CardContent className="py-6 text-center">
141
502
  <div className="space-y-4">
142
503
  <div className="rounded-full bg-purple-100 dark:bg-purple-900/30 p-3 w-fit mx-auto">
@@ -160,8 +521,10 @@ export const HoverCard3D = React.forwardRef<HTMLDivElement, HoverCard3DProps>(
160
521
  )
161
522
  }
162
523
 
163
- return <HoverCard3DInternal className={className} ref={ref} {...props} />
524
+ return <HoverCard3DInternal {...props} ref={ref} />
164
525
  }
165
526
  )
166
527
 
167
- HoverCard3D.displayName = "HoverCard3D"
528
+ HoverCard3D.displayName = "HoverCard3D"
529
+
530
+ export { hoverCard3DVariants }
@@ -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"
@@ -112,4 +116,13 @@ export {
112
116
  type QuizSettings as MoonUIQuizSettings,
113
117
  type UserAnswer as MoonUIUserAnswer,
114
118
  type QuizResult as MoonUIQuizResult
115
- } from "./moonui-quiz-form"
119
+ } from "./moonui-quiz-form"
120
+
121
+ // Gesture Drawer
122
+ export {
123
+ MoonUIGestureDrawerPro,
124
+ GestureDrawer,
125
+ type MoonUIGestureDrawerProProps,
126
+ type GestureDrawerProps,
127
+ moonUIGestureDrawerProVariants
128
+ } from "./gesture-drawer"
@@ -366,7 +366,7 @@ const LazyComponentInternal: React.FC<LazyComponentProps> = ({
366
366
  }
367
367
 
368
368
  // Lazy Image Component
369
- export interface LazyImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
369
+ export interface LazyImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, 'onProgress'> {
370
370
  src: string
371
371
  alt: string
372
372
  fallbackSrc?: string
@@ -409,8 +409,10 @@ export const LazyImage: React.FC<LazyImageProps> = ({
409
409
  srcSet,
410
410
  enableProgressiveLoading = false,
411
411
  onProgress,
412
- ...props
412
+ ...restProps
413
413
  }) => {
414
+ // Filter out LazyImage specific props and event handlers that shouldn't be passed to img element
415
+ const { onDrag, onDragStart, onDragEnd, onDragOver, onDrop, onAnimationStart, onAnimationEnd, onAnimationIteration, ...props } = restProps
414
416
  const [imageSrc, setImageSrc] = useState<string | null>(priority ? src : null)
415
417
  const [imageError, setImageError] = useState(false)
416
418
  const [isVisible, setIsVisible] = useState(priority)
@@ -0,0 +1,29 @@
1
+ import React from 'react'
2
+ import { cn } from '../../lib/utils'
3
+
4
+ interface LicenseErrorProps {
5
+ className?: string
6
+ }
7
+
8
+ export function LicenseError({ className }: LicenseErrorProps) {
9
+ return (
10
+ <div className={cn(
11
+ "flex flex-col items-center justify-center p-8 text-center border-2 border-dashed border-red-500/20 rounded-lg bg-red-50/5",
12
+ className
13
+ )}>
14
+ <div className="text-red-500 mb-4">
15
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
16
+ <path d="M12 2L2 7V12C2 16.5 4.23 20.68 7.62 23.47L12 22L16.38 23.47C19.77 20.68 22 16.5 22 12V7L12 2Z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
17
+ <path d="M12 9V13" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
18
+ <circle cx="12" cy="17" r="1" fill="currentColor"/>
19
+ </svg>
20
+ </div>
21
+ <h3 className="text-lg font-semibold text-red-600 mb-2">License Required</h3>
22
+ <p className="text-sm text-muted-foreground max-w-md">
23
+ This is a Pro component. Please ensure you have a valid MoonUI Pro license to use this component.
24
+ </p>
25
+ </div>
26
+ )
27
+ }
28
+
29
+ export default LicenseError
@@ -831,7 +831,7 @@ export function RealTimePerformanceMonitor({
831
831
  "px-3 py-1 text-xs rounded-md transition-colors",
832
832
  isActive
833
833
  ? "bg-green-500/10 text-green-500 hover:bg-green-500/20"
834
- : "bg-gray-500/10 text-gray-500 hover:bg-gray-500/20"
834
+ : "bg-muted text-muted-foreground hover:bg-muted/80"
835
835
  )}
836
836
  >
837
837
  {isActive ? 'Aktif' : 'Durduruldu'}