@moontra/moonui-pro 2.19.0 → 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.
- package/dist/index.d.ts +3251 -0
- package/dist/index.mjs +2410 -1545
- package/package.json +137 -136
- package/src/__tests__/use-local-storage.test.tsx +2 -2
- package/src/components/advanced-chart/index.tsx +6 -6
- package/src/components/calendar/event-dialog.tsx +1 -1
- package/src/components/calendar/index.tsx +1 -1
- package/src/components/calendar-pro/index.tsx +2 -4
- package/src/components/dashboard/demo.tsx +2 -2
- package/src/components/dashboard/widgets/activity-feed.tsx +1 -1
- package/src/components/dashboard/widgets/metric-card.tsx +1 -1
- package/src/components/enhanced/button.tsx +13 -13
- package/src/components/file-upload/file-upload.test.tsx +20 -19
- package/src/components/form-wizard/form-wizard-progress.tsx +7 -7
- package/src/components/gesture-drawer/index.tsx +551 -0
- package/src/components/github-stars/hooks.ts +1 -1
- package/src/components/github-stars/index.tsx +1 -1
- package/src/components/github-stars/types.ts +1 -0
- package/src/components/health-check/index.tsx +2 -2
- package/src/components/hover-card-3d/index.tsx +437 -74
- package/src/components/index.ts +10 -1
- package/src/components/lazy-component/index.tsx +4 -2
- package/src/components/license-error/index.tsx +29 -0
- package/src/components/memory-efficient-data/index.tsx +1 -1
- package/src/components/pinch-zoom/index.tsx +438 -42
- package/src/components/rich-text-editor/index.tsx +12 -12
- package/src/components/timeline/index.tsx +2 -2
- package/src/components/ui/aspect-ratio.tsx +186 -22
- package/src/components/ui/button.tsx +47 -50
- package/src/components/ui/card.tsx +98 -30
- package/src/components/ui/gesture-drawer.tsx +11 -0
- package/src/components/ui/index.ts +17 -5
- package/src/components/ui/lightbox.tsx +606 -0
- package/src/components/ui/media-gallery.tsx +612 -0
- package/src/components/ui/select.tsx +134 -35
- package/src/components/ui/toggle.tsx +78 -15
- package/src/components/virtual-list/index.tsx +7 -7
- package/src/index.ts +4 -4
- package/src/lib/component-metadata.ts +18 -0
- package/src/lib/paddle.ts +17 -0
- package/src/patterns/login-form/index.tsx +1 -1
- package/src/patterns/login-form/types.ts +6 -6
- package/src/styles/index.css +14 -4
- package/src/types/next-auth.d.ts +21 -0
- package/src/use-local-storage.tsx +3 -3
- package/src/use-scroll-animation.ts +3 -5
- package/src/components/ui/hover-card-3d.tsx +0 -472
|
@@ -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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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,
|
|
36
|
-
|
|
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(
|
|
39
|
-
|
|
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 = (
|
|
49
|
-
const rotateYValue = (
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
(
|
|
131
|
-
//
|
|
493
|
+
(props, ref) => {
|
|
494
|
+
// Pro package - always show component
|
|
132
495
|
const { hasProAccess, isLoading } = useSubscription()
|
|
133
496
|
|
|
134
|
-
//
|
|
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
|
|
524
|
+
return <HoverCard3DInternal {...props} ref={ref} />
|
|
164
525
|
}
|
|
165
526
|
)
|
|
166
527
|
|
|
167
|
-
HoverCard3D.displayName = "HoverCard3D"
|
|
528
|
+
HoverCard3D.displayName = "HoverCard3D"
|
|
529
|
+
|
|
530
|
+
export { hoverCard3DVariants }
|
package/src/components/index.ts
CHANGED
|
@@ -116,4 +116,13 @@ export {
|
|
|
116
116
|
type QuizSettings as MoonUIQuizSettings,
|
|
117
117
|
type UserAnswer as MoonUIUserAnswer,
|
|
118
118
|
type QuizResult as MoonUIQuizResult
|
|
119
|
-
} 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
|
-
...
|
|
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-
|
|
834
|
+
: "bg-muted text-muted-foreground hover:bg-muted/80"
|
|
835
835
|
)}
|
|
836
836
|
>
|
|
837
837
|
{isActive ? 'Aktif' : 'Durduruldu'}
|