@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
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useRef, useState, useCallback, useMemo } from "react"
|
|
4
|
+
import { motion, useMotionValue, useTransform, animate, PanInfo, useAnimation, AnimationControls, useSpring } from "framer-motion"
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
|
+
import { cn } from "../../lib/utils"
|
|
7
|
+
import { X, Lock, Sparkles } from "lucide-react"
|
|
8
|
+
import { useSubscription } from "../../hooks/use-subscription"
|
|
9
|
+
import { Card, CardContent } from "../ui/card"
|
|
10
|
+
import { Button } from "../ui/button"
|
|
11
|
+
|
|
12
|
+
// Gesture Drawer Variants
|
|
13
|
+
const gestureDrawerVariants = cva(
|
|
14
|
+
"fixed bg-background shadow-2xl overflow-hidden",
|
|
15
|
+
{
|
|
16
|
+
variants: {
|
|
17
|
+
position: {
|
|
18
|
+
bottom: "bottom-0 left-0 right-0 rounded-t-[20px] max-h-[95vh]",
|
|
19
|
+
top: "top-0 left-0 right-0 rounded-b-[20px] max-h-[95vh]",
|
|
20
|
+
left: "left-0 top-0 bottom-0 rounded-r-[20px] max-w-[90vw]",
|
|
21
|
+
right: "right-0 top-0 bottom-0 rounded-l-[20px] max-w-[90vw]"
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
default: "",
|
|
25
|
+
sm: "",
|
|
26
|
+
md: "",
|
|
27
|
+
lg: "",
|
|
28
|
+
full: ""
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
compoundVariants: [
|
|
32
|
+
{
|
|
33
|
+
position: ["bottom", "top"],
|
|
34
|
+
size: "sm",
|
|
35
|
+
class: "h-[30vh]"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
position: ["bottom", "top"],
|
|
39
|
+
size: "md",
|
|
40
|
+
class: "h-[50vh]"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
position: ["bottom", "top"],
|
|
44
|
+
size: "lg",
|
|
45
|
+
class: "h-[70vh]"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
position: ["bottom", "top"],
|
|
49
|
+
size: "full",
|
|
50
|
+
class: "h-[95vh]"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
position: ["left", "right"],
|
|
54
|
+
size: "sm",
|
|
55
|
+
class: "w-[280px]"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
position: ["left", "right"],
|
|
59
|
+
size: "md",
|
|
60
|
+
class: "w-[380px]"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
position: ["left", "right"],
|
|
64
|
+
size: "lg",
|
|
65
|
+
class: "w-[480px]"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
position: ["left", "right"],
|
|
69
|
+
size: "full",
|
|
70
|
+
class: "w-[90vw]"
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
defaultVariants: {
|
|
74
|
+
position: "bottom",
|
|
75
|
+
size: "default"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
// Handle/Indicator Variants
|
|
81
|
+
const handleVariants = cva(
|
|
82
|
+
"absolute bg-muted-foreground/20 transition-all duration-200",
|
|
83
|
+
{
|
|
84
|
+
variants: {
|
|
85
|
+
position: {
|
|
86
|
+
bottom: "top-2 left-1/2 -translate-x-1/2 w-12 h-1 rounded-full",
|
|
87
|
+
top: "bottom-2 left-1/2 -translate-x-1/2 w-12 h-1 rounded-full",
|
|
88
|
+
left: "right-2 top-1/2 -translate-y-1/2 w-1 h-12 rounded-full",
|
|
89
|
+
right: "left-2 top-1/2 -translate-y-1/2 w-1 h-12 rounded-full"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
defaultVariants: {
|
|
93
|
+
position: "bottom"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
export interface GestureDrawerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onAnimationStart' | 'onAnimationEnd' | 'onAnimationIteration' | 'onDragStart' | 'onDragEnd' | 'onDrag'>,
|
|
99
|
+
VariantProps<typeof gestureDrawerVariants> {
|
|
100
|
+
// Core props
|
|
101
|
+
isOpen: boolean
|
|
102
|
+
onOpenChange: (open: boolean) => void
|
|
103
|
+
children: React.ReactNode
|
|
104
|
+
|
|
105
|
+
// Position and size
|
|
106
|
+
position?: "bottom" | "top" | "left" | "right"
|
|
107
|
+
size?: "default" | "sm" | "md" | "lg" | "full"
|
|
108
|
+
|
|
109
|
+
// Snap points (percentages of viewport)
|
|
110
|
+
snapPoints?: number[]
|
|
111
|
+
defaultSnapPoint?: number
|
|
112
|
+
|
|
113
|
+
// Gesture options
|
|
114
|
+
enableSwipeToClose?: boolean
|
|
115
|
+
closeThreshold?: number
|
|
116
|
+
closeVelocity?: number
|
|
117
|
+
dragElastic?: number
|
|
118
|
+
|
|
119
|
+
// Visual options
|
|
120
|
+
showHandle?: boolean
|
|
121
|
+
handleClassName?: string
|
|
122
|
+
showCloseButton?: boolean
|
|
123
|
+
closeButtonClassName?: string
|
|
124
|
+
|
|
125
|
+
// Backdrop options
|
|
126
|
+
showBackdrop?: boolean
|
|
127
|
+
backdropClassName?: string
|
|
128
|
+
backdropBlur?: boolean
|
|
129
|
+
closeOnBackdropClick?: boolean
|
|
130
|
+
|
|
131
|
+
// Animation options
|
|
132
|
+
animationDuration?: number
|
|
133
|
+
springConfig?: {
|
|
134
|
+
stiffness?: number
|
|
135
|
+
damping?: number
|
|
136
|
+
mass?: number
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Advanced features
|
|
140
|
+
preventBodyScroll?: boolean
|
|
141
|
+
autoHeight?: boolean
|
|
142
|
+
nestedScrolling?: boolean
|
|
143
|
+
onSnapPointChange?: (snapPoint: number) => void
|
|
144
|
+
|
|
145
|
+
// Component specific
|
|
146
|
+
asChild?: boolean
|
|
147
|
+
isProComponent?: boolean
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Body scroll lock hook
|
|
151
|
+
const useBodyScrollLock = (isLocked: boolean) => {
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (!isLocked) return
|
|
154
|
+
|
|
155
|
+
const originalStyle = window.getComputedStyle(document.body).overflow
|
|
156
|
+
document.body.style.overflow = "hidden"
|
|
157
|
+
|
|
158
|
+
return () => {
|
|
159
|
+
document.body.style.overflow = originalStyle
|
|
160
|
+
}
|
|
161
|
+
}, [isLocked])
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Snap point calculation
|
|
165
|
+
const calculateSnapPoint = (
|
|
166
|
+
offset: number,
|
|
167
|
+
velocity: number,
|
|
168
|
+
snapPoints: number[],
|
|
169
|
+
direction: "up" | "down" | "left" | "right",
|
|
170
|
+
viewportSize: number
|
|
171
|
+
): number => {
|
|
172
|
+
const currentPosition = Math.abs(offset) / viewportSize * 100
|
|
173
|
+
|
|
174
|
+
// Velocity-based snap
|
|
175
|
+
if (Math.abs(velocity) > 500) {
|
|
176
|
+
if ((direction === "up" || direction === "left") && velocity < 0) {
|
|
177
|
+
// Swiping to open more
|
|
178
|
+
const higherPoints = snapPoints.filter(p => p > currentPosition)
|
|
179
|
+
return higherPoints.length > 0 ? higherPoints[0] : snapPoints[snapPoints.length - 1]
|
|
180
|
+
} else if ((direction === "down" || direction === "right") && velocity > 0) {
|
|
181
|
+
// Swiping to close
|
|
182
|
+
const lowerPoints = snapPoints.filter(p => p < currentPosition)
|
|
183
|
+
return lowerPoints.length > 0 ? lowerPoints[lowerPoints.length - 1] : 0
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Find closest snap point
|
|
188
|
+
return snapPoints.reduce((prev, curr) =>
|
|
189
|
+
Math.abs(curr - currentPosition) < Math.abs(prev - currentPosition) ? curr : prev
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const MoonUIGestureDrawerProComponent = React.forwardRef<HTMLDivElement, GestureDrawerProps>(({
|
|
194
|
+
isOpen,
|
|
195
|
+
onOpenChange,
|
|
196
|
+
children,
|
|
197
|
+
position = "bottom",
|
|
198
|
+
size = "default",
|
|
199
|
+
snapPoints = size === "default" ? [25, 50, 75, 100] : [],
|
|
200
|
+
defaultSnapPoint,
|
|
201
|
+
enableSwipeToClose = true,
|
|
202
|
+
closeThreshold = 20,
|
|
203
|
+
closeVelocity = 500,
|
|
204
|
+
dragElastic = 0.2,
|
|
205
|
+
showHandle = true,
|
|
206
|
+
handleClassName,
|
|
207
|
+
showCloseButton = false,
|
|
208
|
+
closeButtonClassName,
|
|
209
|
+
showBackdrop = true,
|
|
210
|
+
backdropClassName,
|
|
211
|
+
backdropBlur = true,
|
|
212
|
+
closeOnBackdropClick = true,
|
|
213
|
+
animationDuration = 0.5,
|
|
214
|
+
springConfig = {
|
|
215
|
+
stiffness: 300,
|
|
216
|
+
damping: 30,
|
|
217
|
+
mass: 1
|
|
218
|
+
},
|
|
219
|
+
preventBodyScroll = true,
|
|
220
|
+
autoHeight = false,
|
|
221
|
+
nestedScrolling = true,
|
|
222
|
+
onSnapPointChange,
|
|
223
|
+
className,
|
|
224
|
+
asChild = false,
|
|
225
|
+
isProComponent = true,
|
|
226
|
+
...props
|
|
227
|
+
}, ref) => {
|
|
228
|
+
const isVertical = position === "bottom" || position === "top"
|
|
229
|
+
const controls = useAnimation()
|
|
230
|
+
const dragControls = useAnimation()
|
|
231
|
+
|
|
232
|
+
// Motion values
|
|
233
|
+
const x = useMotionValue(0)
|
|
234
|
+
const y = useMotionValue(0)
|
|
235
|
+
const motionValue = isVertical ? y : x
|
|
236
|
+
|
|
237
|
+
// State
|
|
238
|
+
const [currentSnapPoint, setCurrentSnapPoint] = useState(
|
|
239
|
+
defaultSnapPoint || (snapPoints.length > 0 ? snapPoints[0] : 50)
|
|
240
|
+
)
|
|
241
|
+
const [isDragging, setIsDragging] = useState(false)
|
|
242
|
+
const contentRef = useRef<HTMLDivElement>(null)
|
|
243
|
+
const [contentHeight, setContentHeight] = useState<number | null>(null)
|
|
244
|
+
|
|
245
|
+
// Body scroll lock
|
|
246
|
+
useBodyScrollLock(isOpen && preventBodyScroll)
|
|
247
|
+
|
|
248
|
+
// Viewport dimensions
|
|
249
|
+
const viewportSize = useMemo(() => {
|
|
250
|
+
if (typeof window === "undefined") return 1000
|
|
251
|
+
return isVertical ? window.innerHeight : window.innerWidth
|
|
252
|
+
}, [isVertical])
|
|
253
|
+
|
|
254
|
+
// Calculate position based on snap point
|
|
255
|
+
const calculatePosition = useCallback((snapPoint: number) => {
|
|
256
|
+
// For snap points, we don't need to calculate positions
|
|
257
|
+
// CVA classes handle the static positioning
|
|
258
|
+
// Motion values should only handle transforms during drag
|
|
259
|
+
return 0
|
|
260
|
+
}, [position, viewportSize])
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
// Backdrop opacity - fixed when drawer is open
|
|
264
|
+
const backdropOpacity = isOpen ? 0.5 : 0
|
|
265
|
+
|
|
266
|
+
// Handle drag end
|
|
267
|
+
const handleDragEnd = useCallback((event: any, info: PanInfo) => {
|
|
268
|
+
setIsDragging(false)
|
|
269
|
+
|
|
270
|
+
const offset = isVertical ? info.offset.y : info.offset.x
|
|
271
|
+
const velocity = isVertical ? info.velocity.y : info.velocity.x
|
|
272
|
+
|
|
273
|
+
// Check if should close
|
|
274
|
+
const shouldClose = enableSwipeToClose && (
|
|
275
|
+
(position === "bottom" && offset > closeThreshold && velocity > -closeVelocity) ||
|
|
276
|
+
(position === "top" && offset < -closeThreshold && velocity < closeVelocity) ||
|
|
277
|
+
(position === "right" && offset > closeThreshold && velocity > -closeVelocity) ||
|
|
278
|
+
(position === "left" && offset < -closeThreshold && velocity < closeVelocity)
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
if (shouldClose) {
|
|
282
|
+
onOpenChange(false)
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Snap to point
|
|
287
|
+
if (snapPoints.length > 0) {
|
|
288
|
+
// Map position to direction for calculateSnapPoint
|
|
289
|
+
const direction = position === "bottom" ? "down" :
|
|
290
|
+
position === "top" ? "up" :
|
|
291
|
+
position === "left" ? "left" : "right"
|
|
292
|
+
|
|
293
|
+
const newSnapPoint = calculateSnapPoint(
|
|
294
|
+
Math.abs(motionValue.get()),
|
|
295
|
+
velocity,
|
|
296
|
+
snapPoints,
|
|
297
|
+
direction,
|
|
298
|
+
viewportSize
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
setCurrentSnapPoint(newSnapPoint)
|
|
302
|
+
onSnapPointChange?.(newSnapPoint)
|
|
303
|
+
|
|
304
|
+
animate(motionValue, calculatePosition(newSnapPoint), {
|
|
305
|
+
type: "spring",
|
|
306
|
+
...springConfig
|
|
307
|
+
})
|
|
308
|
+
} else {
|
|
309
|
+
// Return to original position
|
|
310
|
+
animate(motionValue, calculatePosition(currentSnapPoint), {
|
|
311
|
+
type: "spring",
|
|
312
|
+
...springConfig
|
|
313
|
+
})
|
|
314
|
+
}
|
|
315
|
+
}, [
|
|
316
|
+
isVertical,
|
|
317
|
+
position,
|
|
318
|
+
enableSwipeToClose,
|
|
319
|
+
closeThreshold,
|
|
320
|
+
closeVelocity,
|
|
321
|
+
snapPoints,
|
|
322
|
+
motionValue,
|
|
323
|
+
viewportSize,
|
|
324
|
+
calculatePosition,
|
|
325
|
+
currentSnapPoint,
|
|
326
|
+
springConfig,
|
|
327
|
+
onOpenChange,
|
|
328
|
+
onSnapPointChange
|
|
329
|
+
])
|
|
330
|
+
|
|
331
|
+
// Handle drag start
|
|
332
|
+
const handleDragStart = useCallback((event: any, info: PanInfo) => {
|
|
333
|
+
setIsDragging(true)
|
|
334
|
+
}, [])
|
|
335
|
+
|
|
336
|
+
// Auto height calculation
|
|
337
|
+
useEffect(() => {
|
|
338
|
+
if (!autoHeight || !contentRef.current || !isOpen) return
|
|
339
|
+
|
|
340
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
341
|
+
for (const entry of entries) {
|
|
342
|
+
setContentHeight(entry.contentRect.height)
|
|
343
|
+
}
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
resizeObserver.observe(contentRef.current)
|
|
347
|
+
|
|
348
|
+
return () => {
|
|
349
|
+
resizeObserver.disconnect()
|
|
350
|
+
}
|
|
351
|
+
}, [autoHeight, isOpen])
|
|
352
|
+
|
|
353
|
+
// Animation on open/close - reset transform values
|
|
354
|
+
useEffect(() => {
|
|
355
|
+
if (isOpen) {
|
|
356
|
+
// Reset to zero - CVA handles positioning
|
|
357
|
+
animate(motionValue, 0, {
|
|
358
|
+
type: "spring",
|
|
359
|
+
...springConfig
|
|
360
|
+
})
|
|
361
|
+
} else {
|
|
362
|
+
// Reset transform
|
|
363
|
+
animate(motionValue, 0, {
|
|
364
|
+
type: "spring",
|
|
365
|
+
...springConfig
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
}, [isOpen, motionValue, springConfig])
|
|
369
|
+
|
|
370
|
+
// Keyboard accessibility
|
|
371
|
+
useEffect(() => {
|
|
372
|
+
if (!isOpen) return
|
|
373
|
+
|
|
374
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
375
|
+
if (e.key === "Escape" && enableSwipeToClose) {
|
|
376
|
+
onOpenChange(false)
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
document.addEventListener("keydown", handleKeyDown)
|
|
381
|
+
return () => document.removeEventListener("keydown", handleKeyDown)
|
|
382
|
+
}, [isOpen, enableSwipeToClose, onOpenChange])
|
|
383
|
+
|
|
384
|
+
// Initial position - CVA handles static positioning
|
|
385
|
+
const getInitialPosition = () => {
|
|
386
|
+
return { x: 0, y: 0 }
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Drag constraints - allow reasonable drag movement
|
|
390
|
+
const getDragConstraints = () => {
|
|
391
|
+
switch (position) {
|
|
392
|
+
case "bottom":
|
|
393
|
+
return { top: -200, bottom: 100 }
|
|
394
|
+
case "top":
|
|
395
|
+
return { top: -100, bottom: 200 }
|
|
396
|
+
case "right":
|
|
397
|
+
return { left: -200, right: 100 }
|
|
398
|
+
case "left":
|
|
399
|
+
return { left: -100, right: 200 }
|
|
400
|
+
default:
|
|
401
|
+
return {}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (!isOpen) return null
|
|
406
|
+
|
|
407
|
+
const drawerContent = (
|
|
408
|
+
<motion.div
|
|
409
|
+
initial={{ opacity: 0 }}
|
|
410
|
+
animate={{ opacity: 1 }}
|
|
411
|
+
exit={{ opacity: 0 }}
|
|
412
|
+
transition={{ duration: animationDuration }}
|
|
413
|
+
className="fixed inset-0 z-50"
|
|
414
|
+
style={{ pointerEvents: isDragging ? "none" : "auto" }}
|
|
415
|
+
>
|
|
416
|
+
{/* Backdrop */}
|
|
417
|
+
{showBackdrop && (
|
|
418
|
+
<motion.div
|
|
419
|
+
className={cn(
|
|
420
|
+
"absolute inset-0 bg-black/50",
|
|
421
|
+
backdropBlur && "backdrop-blur-sm",
|
|
422
|
+
backdropClassName
|
|
423
|
+
)}
|
|
424
|
+
style={{ opacity: backdropOpacity }}
|
|
425
|
+
onClick={closeOnBackdropClick ? () => onOpenChange(false) : undefined}
|
|
426
|
+
/>
|
|
427
|
+
)}
|
|
428
|
+
|
|
429
|
+
{/* Drawer */}
|
|
430
|
+
<motion.div
|
|
431
|
+
ref={ref}
|
|
432
|
+
drag={enableSwipeToClose ? (isVertical ? "y" : "x") : false}
|
|
433
|
+
dragConstraints={getDragConstraints()}
|
|
434
|
+
dragElastic={dragElastic}
|
|
435
|
+
onDragStart={handleDragStart}
|
|
436
|
+
onDragEnd={handleDragEnd}
|
|
437
|
+
initial={getInitialPosition()}
|
|
438
|
+
style={{
|
|
439
|
+
...(isDragging ? { [isVertical ? "y" : "x"]: motionValue } : {}),
|
|
440
|
+
...(autoHeight && contentHeight && isVertical
|
|
441
|
+
? { height: `${Math.min(contentHeight + 60, viewportSize * 0.95)}px` }
|
|
442
|
+
: {})
|
|
443
|
+
}}
|
|
444
|
+
className={cn(
|
|
445
|
+
gestureDrawerVariants({ position, size }),
|
|
446
|
+
"will-change-transform",
|
|
447
|
+
className
|
|
448
|
+
)}
|
|
449
|
+
{...props}
|
|
450
|
+
>
|
|
451
|
+
{/* Handle */}
|
|
452
|
+
{showHandle && (
|
|
453
|
+
<div
|
|
454
|
+
className={cn(
|
|
455
|
+
handleVariants({ position }),
|
|
456
|
+
"cursor-grab active:cursor-grabbing",
|
|
457
|
+
isDragging && "bg-muted-foreground/40 scale-x-150",
|
|
458
|
+
handleClassName
|
|
459
|
+
)}
|
|
460
|
+
/>
|
|
461
|
+
)}
|
|
462
|
+
|
|
463
|
+
{/* Close button */}
|
|
464
|
+
{showCloseButton && (
|
|
465
|
+
<button
|
|
466
|
+
onClick={() => onOpenChange(false)}
|
|
467
|
+
className={cn(
|
|
468
|
+
"absolute z-50 p-2 rounded-full bg-background/80 backdrop-blur-sm border shadow-sm",
|
|
469
|
+
"hover:bg-background transition-colors",
|
|
470
|
+
position === "bottom" && "top-3 right-3",
|
|
471
|
+
position === "top" && "bottom-3 right-3",
|
|
472
|
+
position === "left" && "top-3 right-3",
|
|
473
|
+
position === "right" && "top-3 left-3",
|
|
474
|
+
closeButtonClassName
|
|
475
|
+
)}
|
|
476
|
+
aria-label="Close drawer"
|
|
477
|
+
>
|
|
478
|
+
<X className="h-4 w-4" />
|
|
479
|
+
</button>
|
|
480
|
+
)}
|
|
481
|
+
|
|
482
|
+
{/* Content wrapper for nested scrolling */}
|
|
483
|
+
<div
|
|
484
|
+
ref={contentRef}
|
|
485
|
+
className={cn(
|
|
486
|
+
"h-full overflow-auto overscroll-contain",
|
|
487
|
+
nestedScrolling && "touch-pan-y",
|
|
488
|
+
showHandle && position === "bottom" && "pt-2",
|
|
489
|
+
showHandle && position === "top" && "pb-2"
|
|
490
|
+
)}
|
|
491
|
+
style={{
|
|
492
|
+
// Prevent drag when scrolling content
|
|
493
|
+
touchAction: nestedScrolling ? "pan-y" : "none"
|
|
494
|
+
}}
|
|
495
|
+
>
|
|
496
|
+
{children}
|
|
497
|
+
</div>
|
|
498
|
+
</motion.div>
|
|
499
|
+
</motion.div>
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
return drawerContent
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
MoonUIGestureDrawerProComponent.displayName = "MoonUIGestureDrawerProComponent"
|
|
506
|
+
|
|
507
|
+
export const MoonUIGestureDrawerPro = React.forwardRef<
|
|
508
|
+
HTMLDivElement,
|
|
509
|
+
GestureDrawerProps
|
|
510
|
+
>((props, ref) => {
|
|
511
|
+
const { hasProAccess, isLoading } = useSubscription()
|
|
512
|
+
|
|
513
|
+
// Show upgrade prompt if no pro access
|
|
514
|
+
if (!isLoading && !hasProAccess) {
|
|
515
|
+
return (
|
|
516
|
+
<Card className="w-fit mx-auto">
|
|
517
|
+
<CardContent className="py-6 text-center">
|
|
518
|
+
<div className="space-y-4">
|
|
519
|
+
<div className="rounded-full bg-purple-100 dark:bg-purple-900/30 p-3 w-fit mx-auto">
|
|
520
|
+
<Lock className="h-6 w-6 text-purple-600 dark:text-purple-400" />
|
|
521
|
+
</div>
|
|
522
|
+
<div>
|
|
523
|
+
<h3 className="font-semibold text-sm mb-2">Pro Feature</h3>
|
|
524
|
+
<p className="text-muted-foreground text-xs mb-4">
|
|
525
|
+
Gesture Drawer is available exclusively to MoonUI Pro subscribers.
|
|
526
|
+
</p>
|
|
527
|
+
<a href="/pricing">
|
|
528
|
+
<Button size="sm">
|
|
529
|
+
<Sparkles className="mr-2 h-4 w-4" />
|
|
530
|
+
Upgrade to Pro
|
|
531
|
+
</Button>
|
|
532
|
+
</a>
|
|
533
|
+
</div>
|
|
534
|
+
</div>
|
|
535
|
+
</CardContent>
|
|
536
|
+
</Card>
|
|
537
|
+
)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return <MoonUIGestureDrawerProComponent {...props} ref={ref} />
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
MoonUIGestureDrawerPro.displayName = "MoonUIGestureDrawerPro"
|
|
544
|
+
|
|
545
|
+
// Backward compatibility alias
|
|
546
|
+
export const GestureDrawer = MoonUIGestureDrawerPro
|
|
547
|
+
|
|
548
|
+
// Export types
|
|
549
|
+
export type MoonUIGestureDrawerProProps = GestureDrawerProps
|
|
550
|
+
export { gestureDrawerVariants as moonUIGestureDrawerProVariants }
|
|
551
|
+
export default MoonUIGestureDrawerPro
|
|
@@ -66,7 +66,7 @@ export function useGitHubData({
|
|
|
66
66
|
const [rateLimitInfo, setRateLimitInfo] = useState<RateLimitInfo | null>(null)
|
|
67
67
|
const [lastUpdated, setLastUpdated] = useState<Date | null>(null)
|
|
68
68
|
|
|
69
|
-
const refreshTimeoutRef = useRef<NodeJS.Timeout>()
|
|
69
|
+
const refreshTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
|
|
70
70
|
const previousStarsRef = useRef<Map<string, number>>(new Map())
|
|
71
71
|
const errorCountRef = useRef<number>(0) // Hata sayısını takip et
|
|
72
72
|
const maxErrorCount = isDocsMode ? 1 : 2 // Fewer retries in docs mode
|
|
@@ -195,7 +195,7 @@ const HealthCheckInternal: React.FC<HealthCheckProps> = ({
|
|
|
195
195
|
case "warning":
|
|
196
196
|
return <AlertCircle className="h-4 w-4 text-yellow-500" />
|
|
197
197
|
default:
|
|
198
|
-
return <Clock className="h-4 w-4 text-
|
|
198
|
+
return <Clock className="h-4 w-4 text-muted-foreground" />
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -208,7 +208,7 @@ const HealthCheckInternal: React.FC<HealthCheckProps> = ({
|
|
|
208
208
|
case "warning":
|
|
209
209
|
return "bg-yellow-500"
|
|
210
210
|
default:
|
|
211
|
-
return "bg-
|
|
211
|
+
return "bg-muted-foreground"
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|