@moontra/moonui 2.4.4 → 2.4.6

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",
3
- "version": "2.4.4",
3
+ "version": "2.4.6",
4
4
  "description": "Premium React component library with modern design and customization",
5
5
  "author": "MoonUI",
6
6
  "license": "MIT",
@@ -1,54 +1,96 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from "react"
4
- import { motion, useInView, useAnimation, Variants } from "framer-motion"
4
+ import { motion, Variants, Transition, UseInViewOptions } from "framer-motion"
5
5
  import { cn } from "../../lib/utils"
6
6
 
7
+ /**
8
+ * ScrollReveal Component
9
+ *
10
+ * Reveals content with smooth animations when scrolling into view
11
+ * Built with Framer Motion for performance and flexibility
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <ScrollReveal direction="up" delay={0.2}>
16
+ * <Card>Your content</Card>
17
+ * </ScrollReveal>
18
+ * ```
19
+ */
20
+
7
21
  interface ScrollRevealProps {
22
+ /** Content to reveal */
8
23
  children: React.ReactNode
9
- direction?: "up" | "down" | "left" | "right"
24
+ /** Animation direction */
25
+ direction?: "up" | "down" | "left" | "right" | "fade" | "scale" | "blur"
26
+ /** Animation delay in seconds */
10
27
  delay?: number
28
+ /** Animation duration in seconds */
11
29
  duration?: number
30
+ /** Distance to animate from (pixels) */
12
31
  distance?: number
32
+ /** Viewport threshold for trigger (0-1) */
13
33
  threshold?: number
34
+ /** Trigger animation only once */
35
+ once?: boolean
36
+ /** Deprecated: Use 'once' instead */
14
37
  triggerOnce?: boolean
38
+ /** Stagger delay for multiple children (deprecated: use ScrollRevealContainer) */
15
39
  stagger?: number
40
+ /** Additional CSS classes */
16
41
  className?: string
42
+ /** Custom animation variants */
17
43
  variants?: Variants
44
+ /** Enable/disable animations */
18
45
  animate?: boolean
46
+ /** Custom styles */
19
47
  style?: React.CSSProperties
48
+ /** Element ID */
20
49
  id?: string
50
+ /** Viewport options for intersection observer */
51
+ viewport?: UseInViewOptions
21
52
  }
22
53
 
23
- const defaultVariants: Record<string, Variants> = {
24
- up: {
25
- hidden: { opacity: 0, y: 50 },
26
- visible: { opacity: 1, y: 0 }
27
- },
28
- down: {
29
- hidden: { opacity: 0, y: -50 },
30
- visible: { opacity: 1, y: 0 }
31
- },
32
- left: {
33
- hidden: { opacity: 0, x: 50 },
34
- visible: { opacity: 1, x: 0 }
35
- },
36
- right: {
37
- hidden: { opacity: 0, x: -50 },
38
- visible: { opacity: 1, x: 0 }
39
- },
40
- fade: {
41
- hidden: { opacity: 0 },
42
- visible: { opacity: 1 }
43
- },
44
- scale: {
45
- hidden: { opacity: 0, scale: 0.8 },
46
- visible: { opacity: 1, scale: 1 }
47
- },
48
- blur: {
49
- hidden: { opacity: 0, filter: "blur(10px)" },
50
- visible: { opacity: 1, filter: "blur(0px)" }
54
+ // Default animation variants with professional easing
55
+ const createDefaultVariants = (direction: string, distance: number): Variants => {
56
+ const baseVariants: Record<string, Variants> = {
57
+ up: {
58
+ hidden: { opacity: 0, y: distance },
59
+ visible: { opacity: 1, y: 0 }
60
+ },
61
+ down: {
62
+ hidden: { opacity: 0, y: -distance },
63
+ visible: { opacity: 1, y: 0 }
64
+ },
65
+ left: {
66
+ hidden: { opacity: 0, x: distance },
67
+ visible: { opacity: 1, x: 0 }
68
+ },
69
+ right: {
70
+ hidden: { opacity: 0, x: -distance },
71
+ visible: { opacity: 1, x: 0 }
72
+ },
73
+ fade: {
74
+ hidden: { opacity: 0 },
75
+ visible: { opacity: 1 }
76
+ },
77
+ scale: {
78
+ hidden: { opacity: 0, scale: 0.85 },
79
+ visible: { opacity: 1, scale: 1 }
80
+ },
81
+ blur: {
82
+ hidden: { opacity: 0, filter: "blur(10px)" },
83
+ visible: { opacity: 1, filter: "blur(0px)" }
84
+ }
51
85
  }
86
+
87
+ return baseVariants[direction] || baseVariants.up
88
+ }
89
+
90
+ // Professional easing curve
91
+ const defaultTransition: Transition = {
92
+ duration: 0.5,
93
+ ease: [0.25, 0.46, 0.45, 0.94], // Custom cubic-bezier for smooth motion
52
94
  }
53
95
 
54
96
  const ScrollReveal = React.forwardRef<HTMLDivElement, ScrollRevealProps>(
@@ -56,58 +98,47 @@ const ScrollReveal = React.forwardRef<HTMLDivElement, ScrollRevealProps>(
56
98
  children,
57
99
  direction = "up",
58
100
  delay = 0,
59
- duration = 0.6,
101
+ duration = 0.5,
60
102
  distance = 50,
61
- threshold = 0.1,
62
- triggerOnce = true,
103
+ threshold = 0.3, // Increased from 0.1 for better visibility
104
+ once = true,
105
+ triggerOnce, // Backward compatibility
63
106
  stagger = 0,
64
107
  className,
65
108
  variants,
66
109
  animate = true,
67
110
  style,
68
- id
111
+ id,
112
+ viewport
69
113
  }, ref) => {
70
- const controls = useAnimation()
71
- const elementRef = React.useRef<HTMLDivElement>(null)
72
- const isInView = useInView(elementRef, {
73
- amount: threshold,
74
- once: triggerOnce
75
- })
114
+ // Handle backward compatibility
115
+ const shouldTriggerOnce = triggerOnce !== undefined ? triggerOnce : once
76
116
 
77
- // Custom variants with distance
78
- const customVariants = React.useMemo(() => {
117
+ // Get animation variants
118
+ const animationVariants = React.useMemo(() => {
79
119
  if (variants) return variants
80
-
81
- const baseVariants = defaultVariants[direction] || defaultVariants.up
82
-
83
- return {
84
- hidden: {
85
- ...baseVariants.hidden,
86
- ...(direction === "up" && { y: distance }),
87
- ...(direction === "down" && { y: -distance }),
88
- ...(direction === "left" && { x: distance }),
89
- ...(direction === "right" && { x: -distance })
90
- },
91
- visible: baseVariants.visible
92
- }
120
+ return createDefaultVariants(direction, distance)
93
121
  }, [direction, distance, variants])
94
122
 
95
- React.useEffect(() => {
96
- if (!animate) return
97
-
98
- if (isInView) {
99
- controls.start("visible")
100
- } else if (!triggerOnce) {
101
- controls.start("hidden")
102
- }
103
- }, [isInView, controls, triggerOnce, animate])
123
+ // Transition configuration
124
+ const transition = React.useMemo<Transition>(() => ({
125
+ ...defaultTransition,
126
+ duration,
127
+ delay: delay + stagger,
128
+ }), [duration, delay, stagger])
104
129
 
105
- React.useImperativeHandle(ref, () => elementRef.current!)
130
+ // Viewport configuration
131
+ const viewportConfig = React.useMemo<UseInViewOptions>(() => ({
132
+ once: shouldTriggerOnce,
133
+ amount: threshold,
134
+ ...viewport
135
+ }), [shouldTriggerOnce, threshold, viewport])
106
136
 
137
+ // If animations are disabled, render children in a regular div
107
138
  if (!animate) {
108
139
  return (
109
140
  <div
110
- ref={elementRef}
141
+ ref={ref}
111
142
  className={className}
112
143
  style={style}
113
144
  id={id}
@@ -117,17 +148,15 @@ const ScrollReveal = React.forwardRef<HTMLDivElement, ScrollRevealProps>(
117
148
  )
118
149
  }
119
150
 
151
+ // Render with Framer Motion using whileInView pattern
120
152
  return (
121
153
  <motion.div
122
- ref={elementRef}
123
- variants={customVariants}
154
+ ref={ref}
124
155
  initial="hidden"
125
- animate={controls}
126
- transition={{
127
- duration,
128
- delay: delay + stagger,
129
- ease: "easeOut"
130
- }}
156
+ whileInView="visible"
157
+ viewport={viewportConfig}
158
+ variants={animationVariants}
159
+ transition={transition}
131
160
  className={cn(className)}
132
161
  style={style}
133
162
  id={id}
@@ -140,35 +169,82 @@ const ScrollReveal = React.forwardRef<HTMLDivElement, ScrollRevealProps>(
140
169
 
141
170
  ScrollReveal.displayName = "ScrollReveal"
142
171
 
143
- // ScrollReveal container for staggered animations
172
+ /**
173
+ * ScrollRevealContainer Component
174
+ *
175
+ * Container for orchestrating staggered scroll reveal animations
176
+ * Uses Framer Motion's staggerChildren for better performance
177
+ *
178
+ * @example
179
+ * ```tsx
180
+ * <ScrollRevealContainer stagger={0.1}>
181
+ * <ScrollRevealItem>Item 1</ScrollRevealItem>
182
+ * <ScrollRevealItem>Item 2</ScrollRevealItem>
183
+ * </ScrollRevealContainer>
184
+ * ```
185
+ */
186
+
144
187
  interface ScrollRevealContainerProps {
188
+ /** ScrollRevealItem components */
145
189
  children: React.ReactNode
190
+ /** Delay between child animations (seconds) */
146
191
  stagger?: number
192
+ /** Additional CSS classes */
147
193
  className?: string
194
+ /** Custom styles */
148
195
  style?: React.CSSProperties
196
+ /** Element ID */
149
197
  id?: string
198
+ /** Viewport threshold for trigger (0-1) */
199
+ threshold?: number
200
+ /** Trigger animation only once */
201
+ once?: boolean
202
+ /** Deprecated: Use 'once' instead */
203
+ triggerOnce?: boolean
204
+ /** Viewport options for intersection observer */
205
+ viewport?: UseInViewOptions
150
206
  }
151
207
 
152
208
  const ScrollRevealContainer = React.forwardRef<HTMLDivElement, ScrollRevealContainerProps>(
153
- ({ children, stagger = 0.1, className, style, id }, ref) => {
154
- const containerRef = React.useRef<HTMLDivElement>(null)
155
- const isInView = useInView(containerRef, { amount: 0.1, once: true })
209
+ ({
210
+ children,
211
+ stagger = 0.1,
212
+ className,
213
+ style,
214
+ id,
215
+ threshold = 0.3,
216
+ once = true,
217
+ triggerOnce,
218
+ viewport
219
+ }, ref) => {
220
+ // Handle backward compatibility
221
+ const shouldTriggerOnce = triggerOnce !== undefined ? triggerOnce : once
156
222
 
157
- React.useImperativeHandle(ref, () => containerRef.current!)
223
+ // Viewport configuration
224
+ const viewportConfig = React.useMemo<UseInViewOptions>(() => ({
225
+ once: shouldTriggerOnce,
226
+ amount: threshold,
227
+ ...viewport
228
+ }), [shouldTriggerOnce, threshold, viewport])
229
+
230
+ // Container variants for staggered children
231
+ const containerVariants: Variants = {
232
+ hidden: {},
233
+ visible: {
234
+ transition: {
235
+ staggerChildren: stagger,
236
+ delayChildren: 0
237
+ }
238
+ }
239
+ }
158
240
 
159
241
  return (
160
242
  <motion.div
161
- ref={containerRef}
243
+ ref={ref}
162
244
  initial="hidden"
163
- animate={isInView ? "visible" : "hidden"}
164
- variants={{
165
- hidden: {},
166
- visible: {
167
- transition: {
168
- staggerChildren: stagger
169
- }
170
- }
171
- }}
245
+ whileInView="visible"
246
+ viewport={viewportConfig}
247
+ variants={containerVariants}
172
248
  className={cn(className)}
173
249
  style={style}
174
250
  id={id}
@@ -181,15 +257,36 @@ const ScrollRevealContainer = React.forwardRef<HTMLDivElement, ScrollRevealConta
181
257
 
182
258
  ScrollRevealContainer.displayName = "ScrollRevealContainer"
183
259
 
184
- // ScrollReveal item for use within containers
260
+ /**
261
+ * ScrollRevealItem Component
262
+ *
263
+ * Individual item within a ScrollRevealContainer
264
+ * Automatically inherits timing from parent container
265
+ *
266
+ * @example
267
+ * ```tsx
268
+ * <ScrollRevealItem direction="up">
269
+ * <Card>Item content</Card>
270
+ * </ScrollRevealItem>
271
+ * ```
272
+ */
273
+
185
274
  interface ScrollRevealItemProps {
275
+ /** Content to animate */
186
276
  children: React.ReactNode
187
- direction?: "up" | "down" | "left" | "right"
277
+ /** Animation direction */
278
+ direction?: "up" | "down" | "left" | "right" | "fade" | "scale" | "blur"
279
+ /** Animation duration in seconds */
188
280
  duration?: number
281
+ /** Distance to animate from (pixels) */
189
282
  distance?: number
283
+ /** Additional CSS classes */
190
284
  className?: string
285
+ /** Custom animation variants */
191
286
  variants?: Variants
287
+ /** Custom styles */
192
288
  style?: React.CSSProperties
289
+ /** Element ID */
193
290
  id?: string
194
291
  }
195
292
 
@@ -197,38 +294,30 @@ const ScrollRevealItem = React.forwardRef<HTMLDivElement, ScrollRevealItemProps>
197
294
  ({
198
295
  children,
199
296
  direction = "up",
200
- duration = 0.6,
297
+ duration = 0.5,
201
298
  distance = 50,
202
299
  className,
203
300
  variants,
204
301
  style,
205
302
  id
206
303
  }, ref) => {
207
- const customVariants = React.useMemo(() => {
304
+ // Get animation variants
305
+ const animationVariants = React.useMemo(() => {
208
306
  if (variants) return variants
209
-
210
- const baseVariants = defaultVariants[direction] || defaultVariants.up
211
-
212
- return {
213
- hidden: {
214
- ...baseVariants.hidden,
215
- ...(direction === "up" && { y: distance }),
216
- ...(direction === "down" && { y: -distance }),
217
- ...(direction === "left" && { x: distance }),
218
- ...(direction === "right" && { x: -distance })
219
- },
220
- visible: baseVariants.visible
221
- }
307
+ return createDefaultVariants(direction, distance)
222
308
  }, [direction, distance, variants])
223
309
 
310
+ // Transition configuration
311
+ const transition = React.useMemo<Transition>(() => ({
312
+ ...defaultTransition,
313
+ duration,
314
+ }), [duration])
315
+
224
316
  return (
225
317
  <motion.div
226
318
  ref={ref}
227
- variants={customVariants}
228
- transition={{
229
- duration,
230
- ease: "easeOut"
231
- }}
319
+ variants={animationVariants}
320
+ transition={transition}
232
321
  className={cn(className)}
233
322
  style={style}
234
323
  id={id}
@@ -242,4 +331,4 @@ const ScrollRevealItem = React.forwardRef<HTMLDivElement, ScrollRevealItemProps>
242
331
  ScrollRevealItem.displayName = "ScrollRevealItem"
243
332
 
244
333
  export { ScrollReveal, ScrollRevealContainer, ScrollRevealItem }
245
- export type { ScrollRevealProps, ScrollRevealContainerProps, ScrollRevealItemProps }
334
+ export type { ScrollRevealProps, ScrollRevealContainerProps, ScrollRevealItemProps }