react-ui-animate 5.3.0-next.3 → 5.3.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 (3) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +743 -743
  3. package/package.json +73 -73
package/README.md CHANGED
@@ -1,743 +1,743 @@
1
- # React UI Animate
2
-
3
- [![npm version](https://badge.fury.io/js/react-ui-animate.svg)](https://badge.fury.io/js/react-ui-animate)
4
-
5
- > Create smooth animations and interactive gestures in React applications effortlessly.
6
-
7
- ## Installation
8
-
9
- ```sh
10
- npm install react-ui-animate
11
- ```
12
-
13
- ```sh
14
- yarn add react-ui-animate
15
- ```
16
-
17
- ---
18
-
19
- ## Quick Start
20
-
21
- The `react-ui-animate` library provides a declarative way to add animations and gestures to your React components. Here's a simple example:
22
-
23
- ```tsx
24
- import { animate, withSpring } from 'react-ui-animate';
25
-
26
- function App() {
27
- return (
28
- <animate.div
29
- style={{
30
- width: 100,
31
- height: 100,
32
- backgroundColor: 'blue',
33
- scale: 0.5,
34
- opacity: 0,
35
- }}
36
- animate={{
37
- scale: withSpring(1),
38
- opacity: withSpring(1),
39
- }}
40
- />
41
- );
42
- }
43
- ```
44
-
45
- ---
46
-
47
- ## Core Concepts
48
-
49
- ### 1. Animate Component
50
-
51
- The `animate` object provides animated versions of all HTML elements. Use `animate.div`, `animate.button`, `animate.span`, etc., just like regular React elements.
52
-
53
- #### Basic Animation
54
-
55
- Use the `animate` prop to define animations that run when the component mounts or when the prop changes:
56
-
57
- ```tsx
58
- import { animate, withSpring, withTiming } from 'react-ui-animate';
59
-
60
- <animate.div
61
- style={{
62
- width: 100,
63
- height: 100,
64
- backgroundColor: 'red',
65
- translateX: 0,
66
- }}
67
- animate={{
68
- translateX: withSpring(200),
69
- backgroundColor: withTiming('blue', { duration: 500 }),
70
- }}
71
- />
72
- ```
73
-
74
- #### Exit Animations with Presence
75
-
76
- Wrap components in `Presence` to enable exit animations when they're removed:
77
-
78
- ```tsx
79
- import { Presence, animate, withSpring, withTiming } from 'react-ui-animate';
80
-
81
- function Modal({ isOpen, onClose }) {
82
- return (
83
- <Presence>
84
- {isOpen && (
85
- <animate.div
86
- key="modal"
87
- style={{
88
- opacity: 0,
89
- scale: 0.8,
90
- }}
91
- animate={{
92
- opacity: withTiming(1),
93
- scale: withSpring(1),
94
- }}
95
- exit={{
96
- opacity: withTiming(0),
97
- scale: withSpring(0.8),
98
- }}
99
- >
100
- Modal Content
101
- </animate.div>
102
- )}
103
- </Presence>
104
- );
105
- }
106
- ```
107
-
108
- #### State-Based Animations
109
-
110
- React to user interactions with `hover`, `press`, `focus`, and `view` props:
111
-
112
- ```tsx
113
- <animate.button
114
- style={{
115
- scale: 1,
116
- backgroundColor: '#3399ff',
117
- }}
118
- hover={{
119
- scale: withSpring(1.05),
120
- backgroundColor: withTiming('#4da6ff'),
121
- }}
122
- press={{
123
- scale: withSpring(0.95),
124
- }}
125
- >
126
- Hover Me
127
- </animate.button>
128
- ```
129
-
130
- **View Animations** - Animate when elements enter the viewport:
131
-
132
- ```tsx
133
- <animate.div
134
- style={{
135
- opacity: 0,
136
- translateY: 50,
137
- }}
138
- view={{
139
- opacity: withTiming(1),
140
- translateY: withSpring(0),
141
- }}
142
- viewOptions={{ threshold: 0.3, once: true }}
143
- >
144
- This animates when scrolled into view
145
- </animate.div>
146
- ```
147
-
148
- ### 2. useValue Hook
149
-
150
- Create and control animated values programmatically:
151
-
152
- ```tsx
153
- import { useValue, animate, withSpring, withSequence, withTiming } from 'react-ui-animate';
154
-
155
- function AnimatedBox() {
156
- const [width, setWidth] = useValue(100);
157
- const [x, setX] = useValue(0);
158
-
159
- return (
160
- <>
161
- <button onClick={() => setWidth(withSpring(200))}>
162
- Expand
163
- </button>
164
- <button onClick={() => setX(withSequence([
165
- withTiming(100, { duration: 300 }),
166
- withTiming(200, { duration: 300 }),
167
- withTiming(0, { duration: 300 }),
168
- ]))}>
169
- Sequence
170
- </button>
171
-
172
- <animate.div
173
- style={{
174
- width,
175
- height: 100,
176
- backgroundColor: 'red',
177
- translateX: x,
178
- }}
179
- />
180
- </>
181
- );
182
- }
183
- ```
184
-
185
- **Interpolation** - Map values to different ranges:
186
-
187
- ```tsx
188
- const [progress, setProgress] = useValue(0);
189
-
190
- <animate.div
191
- style={{
192
- backgroundColor: progress.to([0, 1], ['red', 'blue']),
193
- translateX: progress.to([0, 1], [0, 500]),
194
- }}
195
- />
196
- ```
197
-
198
- **Controls** - Control animations programmatically:
199
-
200
- ```tsx
201
- const [value, setValue, controls] = useValue(0);
202
-
203
- // Start animation
204
- setValue(withSpring(100));
205
-
206
- // Control playback
207
- controls.pause();
208
- controls.resume();
209
- controls.cancel();
210
- controls.reset();
211
- ```
212
-
213
- ### 3. Animation Descriptors
214
-
215
- Animation descriptors define how animations behave. They can be used with both `animate` components and `useValue`.
216
-
217
- #### withSpring
218
-
219
- Creates physics-based spring animations:
220
-
221
- ```tsx
222
- withSpring(100, {
223
- stiffness: 100, // Spring stiffness (default: 100)
224
- damping: 15, // Spring damping (default: 15)
225
- mass: 1, // Spring mass (default: 1)
226
- })
227
- ```
228
-
229
- #### withTiming
230
-
231
- Creates time-based animations with easing:
232
-
233
- ```tsx
234
- withTiming(100, {
235
- duration: 500, // Duration in milliseconds
236
- easing: Easing.easeInOut, // Easing function
237
- })
238
- ```
239
-
240
- #### withDecay
241
-
242
- Creates momentum-based decay animations:
243
-
244
- ```tsx
245
- withDecay({
246
- velocity: 100, // Initial velocity
247
- clamp: [0, 500], // Optional: clamp values
248
- })
249
- ```
250
-
251
- #### withSequence
252
-
253
- Runs animations one after another:
254
-
255
- ```tsx
256
- withSequence([
257
- withTiming(100, { duration: 300 }),
258
- withTiming(200, { duration: 300 }),
259
- withSpring(0, { stiffness: 200 }),
260
- ])
261
- ```
262
-
263
- #### withLoop
264
-
265
- Repeats animations:
266
-
267
- ```tsx
268
- withLoop(
269
- withSequence([
270
- withTiming(90, { duration: 500 }),
271
- withTiming(180, { duration: 500 }),
272
- withTiming(360, { duration: 500 }),
273
- ]),
274
- 3 // Number of iterations (0 = infinite)
275
- )
276
- ```
277
-
278
- #### withDelay
279
-
280
- Adds delay to animations (typically used inside `withSequence`):
281
-
282
- ```tsx
283
- withSequence([
284
- withDelay(500),
285
- withTiming(1, { duration: 500 }),
286
- ])
287
- ```
288
-
289
- ### 4. Animation Recipes
290
-
291
- Pre-built animation recipes for common use cases:
292
-
293
- ```tsx
294
- import {
295
- animate,
296
- fadeIn,
297
- slideInUp,
298
- scaleIn,
299
- bounceIn,
300
- hoverScale,
301
- pressScale,
302
- } from 'react-ui-animate';
303
-
304
- // Enter animations
305
- <animate.div animate={fadeIn}>Fades in</animate.div>
306
- <animate.div animate={slideInUp}>Slides up</animate.div>
307
- <animate.div animate={scaleIn}>Scales in</animate.div>
308
- <animate.div animate={bounceIn}>Bounces in</animate.div>
309
-
310
- // State animations
311
- <animate.button hover={hoverScale} press={pressScale}>
312
- Interactive Button
313
- </animate.button>
314
-
315
- // Exit animations
316
- <animate.div exit={exitFade}>Fades out</animate.div>
317
- ```
318
-
319
- **Available Recipes:**
320
-
321
- - **Fade**: `fadeIn`, `fadeOut`, `fadeInUp`, `fadeInDown`, `fadeInLeft`, `fadeInRight`
322
- - **Slide**: `slideInUp`, `slideInDown`, `slideInLeft`, `slideInRight`, `slideOutUp`, `slideOutDown`, `slideOutLeft`, `slideOutRight`
323
- - **Scale**: `scaleIn`, `scaleOut`, `scaleUp`, `scaleDown`
324
- - **Bounce**: `bounceIn`, `bounceOut`
325
- - **Rotate**: `rotateIn`, `rotateOut`, `spin`
326
- - **Zoom**: `zoomIn`, `zoomOut`
327
- - **Flip**: `flipX`, `flipY`
328
- - **Combined**: `slideFadeIn`, `slideFadeOut`, `scaleFadeIn`, `scaleFadeOut`
329
- - **Hover**: `hoverScale`, `hoverLift`, `hoverGlow`
330
- - **Press**: `pressScale`, `pressDown`
331
- - **Exit**: `exitFade`, `exitSlideUp`, `exitSlideDown`, `exitScale`
332
-
333
- ### 5. Presence Component
334
-
335
- `Presence` manages mount and unmount animations for components:
336
-
337
- ```tsx
338
- import { Presence, animate, withSpring } from 'react-ui-animate';
339
-
340
- function List() {
341
- const [items, setItems] = useState(['Item 1', 'Item 2']);
342
-
343
- return (
344
- <Presence mode="sync" onExitComplete={() => console.log('All exited')}>
345
- {items.map((item) => (
346
- <animate.div
347
- key={item}
348
- animate={{ opacity: withSpring(1) }}
349
- exit={{ opacity: withSpring(0) }}
350
- >
351
- {item}
352
- </animate.div>
353
- ))}
354
- </Presence>
355
- );
356
- }
357
- ```
358
-
359
- **Presence Props:**
360
-
361
- - `mode`: `'sync'` (default) | `'wait'` | `'popLayout'`
362
- - `sync`: Exiting and entering animate simultaneously
363
- - `wait`: Exiting complete before entering start
364
- - `popLayout`: Exiting removed from layout immediately
365
- - `initial`: Skip enter animation on initial mount (default: `true`)
366
- - `onExitComplete`: Callback when all exits complete
367
-
368
- **Presence Hooks:**
369
-
370
- ```tsx
371
- import { usePresence, useIsPresent } from 'react-ui-animate';
372
-
373
- function AnimatedItem() {
374
- const [isPresent, onExitComplete] = usePresence();
375
- const isPresent2 = useIsPresent(); // Simple boolean check
376
-
377
- // Use isPresent to conditionally render or animate
378
- return isPresent ? <div>Content</div> : null;
379
- }
380
- ```
381
-
382
- ### 6. Gestures
383
-
384
- React to user gestures with built-in hooks:
385
-
386
- #### useDrag
387
-
388
- Handle drag gestures:
389
-
390
- ```tsx
391
- import { useValue, animate, useDrag, withSpring } from 'react-ui-animate';
392
-
393
- function Draggable() {
394
- const ref = useRef(null);
395
- const [x, setX] = useValue(0);
396
- const [y, setY] = useValue(0);
397
-
398
- useDrag(ref, ({ down, movement }) => {
399
- if (down) {
400
- setX(movement.x);
401
- setY(movement.y);
402
- } else {
403
- setX(withSpring(0));
404
- setY(withSpring(0));
405
- }
406
- });
407
-
408
- return (
409
- <animate.div
410
- ref={ref}
411
- style={{
412
- width: 100,
413
- height: 100,
414
- backgroundColor: 'blue',
415
- translateX: x,
416
- translateY: y,
417
- }}
418
- />
419
- );
420
- }
421
- ```
422
-
423
- #### useMove
424
-
425
- Track pointer movement:
426
-
427
- ```tsx
428
- import { useMove } from 'react-ui-animate';
429
-
430
- useMove(ref, ({ movement }) => {
431
- console.log('Moving:', movement.x, movement.y);
432
- });
433
- ```
434
-
435
- #### useScroll
436
-
437
- React to scroll events:
438
-
439
- ```tsx
440
- import { useScroll } from 'react-ui-animate';
441
-
442
- useScroll(ref, ({ scroll }) => {
443
- console.log('Scrolled:', scroll.x, scroll.y);
444
- });
445
- ```
446
-
447
- #### useWheel
448
-
449
- Handle wheel events:
450
-
451
- ```tsx
452
- import { useWheel } from 'react-ui-animate';
453
-
454
- useWheel(ref, ({ delta }) => {
455
- console.log('Wheel delta:', delta.x, delta.y);
456
- });
457
- ```
458
-
459
- #### useScrollProgress
460
-
461
- Track scroll progress:
462
-
463
- ```tsx
464
- import { useScrollProgress } from 'react-ui-animate';
465
-
466
- const progress = useScrollProgress(ref, {
467
- start: 0, // Start tracking at 0% scroll
468
- end: 100, // End tracking at 100% scroll
469
- axis: 'y', // 'x' or 'y'
470
- });
471
- ```
472
-
473
- ### 7. Utilities
474
-
475
- #### makeAnimated
476
-
477
- Create custom animated components:
478
-
479
- ```tsx
480
- import { makeAnimated } from 'react-ui-animate';
481
-
482
- const AnimatedButton = makeAnimated('button');
483
- const AnimatedSection = makeAnimated('section');
484
-
485
- <AnimatedButton animate={{ scale: withSpring(1.1) }}>
486
- Custom Button
487
- </AnimatedButton>
488
- ```
489
-
490
- #### to (Interpolation)
491
-
492
- Map values between ranges:
493
-
494
- ```tsx
495
- import { to } from 'react-ui-animate';
496
-
497
- const interpolate = to([0, 100], [0, 500]);
498
- interpolate(50); // Returns 250
499
-
500
- // Color interpolation
501
- const colorInterpolate = to([0, 1], ['red', 'blue']);
502
- colorInterpolate(0.5); // Returns interpolated color
503
- ```
504
-
505
- #### combine
506
-
507
- Combine multiple animated values:
508
-
509
- ```tsx
510
- import { combine, useValue } from 'react-ui-animate';
511
-
512
- const [x, setX] = useValue(0);
513
- const [y, setY] = useValue(0);
514
- const combined = combine(x, y, (x, y) => x + y);
515
- ```
516
-
517
- ### 8. Additional Hooks
518
-
519
- #### useInView
520
-
521
- Detect when elements enter the viewport:
522
-
523
- ```tsx
524
- import { useInView } from 'react-ui-animate';
525
-
526
- const ref = useRef(null);
527
- const isInView = useInView(ref, {
528
- threshold: 0.5,
529
- once: true,
530
- });
531
- ```
532
-
533
- #### useOutsideClick
534
-
535
- Detect clicks outside an element:
536
-
537
- ```tsx
538
- import { useOutsideClick } from 'react-ui-animate';
539
-
540
- const ref = useRef(null);
541
- useOutsideClick(ref, () => {
542
- console.log('Clicked outside!');
543
- });
544
- ```
545
-
546
- ---
547
-
548
- ## Complete Examples
549
-
550
- ### Modal with Exit Animation
551
-
552
- ```tsx
553
- import { useState, useRef } from 'react';
554
- import {
555
- Presence,
556
- animate,
557
- useOutsideClick,
558
- withSpring,
559
- withTiming,
560
- } from 'react-ui-animate';
561
-
562
- function Modal({ isOpen, onClose }) {
563
- const ref = useRef(null);
564
- useOutsideClick(ref, onClose);
565
-
566
- return (
567
- <Presence>
568
- {isOpen && (
569
- <>
570
- {/* Backdrop */}
571
- <animate.div
572
- key="backdrop"
573
- style={{
574
- position: 'fixed',
575
- inset: 0,
576
- backgroundColor: 'rgba(0,0,0,0)',
577
- opacity: 0,
578
- }}
579
- animate={{
580
- backgroundColor: withTiming('rgba(0,0,0,0.5)'),
581
- opacity: withTiming(1),
582
- }}
583
- exit={{
584
- backgroundColor: withTiming('rgba(0,0,0,0)'),
585
- opacity: withTiming(0),
586
- }}
587
- />
588
-
589
- {/* Modal */}
590
- <animate.div
591
- key="modal"
592
- ref={ref}
593
- style={{
594
- position: 'fixed',
595
- inset: 0,
596
- display: 'flex',
597
- alignItems: 'center',
598
- justifyContent: 'center',
599
- scale: 0.8,
600
- opacity: 0,
601
- }}
602
- animate={{
603
- scale: withSpring(1),
604
- opacity: withSpring(1),
605
- }}
606
- exit={{
607
- scale: withSpring(0.8),
608
- opacity: withSpring(0),
609
- }}
610
- >
611
- <div style={{ backgroundColor: 'white', padding: 20 }}>
612
- Modal Content
613
- </div>
614
- </animate.div>
615
- </>
616
- )}
617
- </Presence>
618
- );
619
- }
620
- ```
621
-
622
- ### Scroll-Triggered Animations
623
-
624
- ```tsx
625
- import { animate, withSpring, withTiming } from 'react-ui-animate';
626
-
627
- function FeatureCard({ title, description }) {
628
- return (
629
- <animate.div
630
- style={{
631
- opacity: 0,
632
- translateY: 50,
633
- scale: 0.9,
634
- }}
635
- view={{
636
- opacity: withTiming(1, { duration: 600 }),
637
- translateY: withSpring(0),
638
- scale: withSpring(1),
639
- }}
640
- viewOptions={{ threshold: 0.3, once: true }}
641
- >
642
- <h3>{title}</h3>
643
- <p>{description}</p>
644
- </animate.div>
645
- );
646
- }
647
- ```
648
-
649
- ### Interactive Button
650
-
651
- ```tsx
652
- import { animate, withSpring, hoverScale, pressScale } from 'react-ui-animate';
653
-
654
- <animate.button
655
- style={{
656
- padding: '12px 24px',
657
- backgroundColor: '#3399ff',
658
- color: 'white',
659
- border: 'none',
660
- borderRadius: 8,
661
- cursor: 'pointer',
662
- }}
663
- hover={hoverScale}
664
- press={pressScale}
665
- >
666
- Click Me
667
- </animate.button>
668
- ```
669
-
670
- ---
671
-
672
- ## API Reference
673
-
674
- ### Animation Descriptors
675
-
676
- | Descriptor | Description | Options |
677
- |------------|-------------|---------|
678
- | `withSpring(to, options?)` | Physics-based spring | `stiffness`, `damping`, `mass`, `from`, callbacks |
679
- | `withTiming(to, options?)` | Time-based animation | `duration`, `easing`, `from`, callbacks |
680
- | `withDecay(options)` | Momentum decay | `velocity`, `clamp`, callbacks |
681
- | `withSequence(animations)` | Run sequentially | `animations` array, callbacks |
682
- | `withLoop(animation, iterations)` | Repeat animation | `iterations` (0 = infinite), callbacks |
683
- | `withDelay(ms)` | Add delay | `delay` in milliseconds |
684
-
685
- ### Animate Component Props
686
-
687
- | Prop | Type | Description |
688
- |------|------|-------------|
689
- | `animate` | `AnimateProp` | Animations on mount/update |
690
- | `exit` | `AnimateProp` | Animations on unmount (requires `Presence`) |
691
- | `hover` | `AnimateProp` | Animations on hover |
692
- | `press` | `AnimateProp` | Animations on press (mousedown/touchstart) |
693
- | `focus` | `AnimateProp` | Animations on focus |
694
- | `view` | `AnimateProp` | Animations when entering viewport |
695
- | `viewOptions` | `UseInViewOptions` | IntersectionObserver options |
696
-
697
- ### Callbacks
698
-
699
- All descriptors support optional callbacks:
700
-
701
- ```tsx
702
- withSpring(100, {
703
- onStart: () => console.log('Started'),
704
- onChange: (value) => console.log('Value:', value),
705
- onComplete: () => console.log('Completed'),
706
- })
707
- ```
708
-
709
- ---
710
-
711
- ## TypeScript Support
712
-
713
- Full TypeScript support is included. All components, hooks, and utilities are fully typed.
714
-
715
- ---
716
-
717
- ## Performance
718
-
719
- - Animations run on the GPU when possible
720
- - Automatic batching of style updates
721
- - Optimized re-renders
722
- - Tree-shakeable exports
723
-
724
- ---
725
-
726
- ## Browser Support
727
-
728
- - Chrome/Edge (latest)
729
- - Firefox (latest)
730
- - Safari (latest)
731
- - Mobile browsers (iOS Safari, Chrome Mobile)
732
-
733
- ---
734
-
735
- ## Documentation
736
-
737
- For detailed documentation and more examples, visit the [official documentation](https://react-ui-animate.js.org/).
738
-
739
- ---
740
-
741
- ## License
742
-
743
- MIT © [Dipesh Rai](https://github.com/dipeshrai123)
1
+ # React UI Animate
2
+
3
+ [![npm version](https://badge.fury.io/js/react-ui-animate.svg)](https://badge.fury.io/js/react-ui-animate)
4
+
5
+ > Create smooth animations and interactive gestures in React applications effortlessly.
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ npm install react-ui-animate
11
+ ```
12
+
13
+ ```sh
14
+ yarn add react-ui-animate
15
+ ```
16
+
17
+ ---
18
+
19
+ ## Quick Start
20
+
21
+ The `react-ui-animate` library provides a declarative way to add animations and gestures to your React components. Here's a simple example:
22
+
23
+ ```tsx
24
+ import { animate, withSpring } from 'react-ui-animate';
25
+
26
+ function App() {
27
+ return (
28
+ <animate.div
29
+ style={{
30
+ width: 100,
31
+ height: 100,
32
+ backgroundColor: 'blue',
33
+ scale: 0.5,
34
+ opacity: 0,
35
+ }}
36
+ animate={{
37
+ scale: withSpring(1),
38
+ opacity: withSpring(1),
39
+ }}
40
+ />
41
+ );
42
+ }
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Core Concepts
48
+
49
+ ### 1. Animate Component
50
+
51
+ The `animate` object provides animated versions of all HTML elements. Use `animate.div`, `animate.button`, `animate.span`, etc., just like regular React elements.
52
+
53
+ #### Basic Animation
54
+
55
+ Use the `animate` prop to define animations that run when the component mounts or when the prop changes:
56
+
57
+ ```tsx
58
+ import { animate, withSpring, withTiming } from 'react-ui-animate';
59
+
60
+ <animate.div
61
+ style={{
62
+ width: 100,
63
+ height: 100,
64
+ backgroundColor: 'red',
65
+ translateX: 0,
66
+ }}
67
+ animate={{
68
+ translateX: withSpring(200),
69
+ backgroundColor: withTiming('blue', { duration: 500 }),
70
+ }}
71
+ />
72
+ ```
73
+
74
+ #### Exit Animations with Presence
75
+
76
+ Wrap components in `Presence` to enable exit animations when they're removed:
77
+
78
+ ```tsx
79
+ import { Presence, animate, withSpring, withTiming } from 'react-ui-animate';
80
+
81
+ function Modal({ isOpen, onClose }) {
82
+ return (
83
+ <Presence>
84
+ {isOpen && (
85
+ <animate.div
86
+ key="modal"
87
+ style={{
88
+ opacity: 0,
89
+ scale: 0.8,
90
+ }}
91
+ animate={{
92
+ opacity: withTiming(1),
93
+ scale: withSpring(1),
94
+ }}
95
+ exit={{
96
+ opacity: withTiming(0),
97
+ scale: withSpring(0.8),
98
+ }}
99
+ >
100
+ Modal Content
101
+ </animate.div>
102
+ )}
103
+ </Presence>
104
+ );
105
+ }
106
+ ```
107
+
108
+ #### State-Based Animations
109
+
110
+ React to user interactions with `hover`, `press`, `focus`, and `view` props:
111
+
112
+ ```tsx
113
+ <animate.button
114
+ style={{
115
+ scale: 1,
116
+ backgroundColor: '#3399ff',
117
+ }}
118
+ hover={{
119
+ scale: withSpring(1.05),
120
+ backgroundColor: withTiming('#4da6ff'),
121
+ }}
122
+ press={{
123
+ scale: withSpring(0.95),
124
+ }}
125
+ >
126
+ Hover Me
127
+ </animate.button>
128
+ ```
129
+
130
+ **View Animations** - Animate when elements enter the viewport:
131
+
132
+ ```tsx
133
+ <animate.div
134
+ style={{
135
+ opacity: 0,
136
+ translateY: 50,
137
+ }}
138
+ view={{
139
+ opacity: withTiming(1),
140
+ translateY: withSpring(0),
141
+ }}
142
+ viewOptions={{ threshold: 0.3, once: true }}
143
+ >
144
+ This animates when scrolled into view
145
+ </animate.div>
146
+ ```
147
+
148
+ ### 2. useValue Hook
149
+
150
+ Create and control animated values programmatically:
151
+
152
+ ```tsx
153
+ import { useValue, animate, withSpring, withSequence, withTiming } from 'react-ui-animate';
154
+
155
+ function AnimatedBox() {
156
+ const [width, setWidth] = useValue(100);
157
+ const [x, setX] = useValue(0);
158
+
159
+ return (
160
+ <>
161
+ <button onClick={() => setWidth(withSpring(200))}>
162
+ Expand
163
+ </button>
164
+ <button onClick={() => setX(withSequence([
165
+ withTiming(100, { duration: 300 }),
166
+ withTiming(200, { duration: 300 }),
167
+ withTiming(0, { duration: 300 }),
168
+ ]))}>
169
+ Sequence
170
+ </button>
171
+
172
+ <animate.div
173
+ style={{
174
+ width,
175
+ height: 100,
176
+ backgroundColor: 'red',
177
+ translateX: x,
178
+ }}
179
+ />
180
+ </>
181
+ );
182
+ }
183
+ ```
184
+
185
+ **Interpolation** - Map values to different ranges:
186
+
187
+ ```tsx
188
+ const [progress, setProgress] = useValue(0);
189
+
190
+ <animate.div
191
+ style={{
192
+ backgroundColor: progress.to([0, 1], ['red', 'blue']),
193
+ translateX: progress.to([0, 1], [0, 500]),
194
+ }}
195
+ />
196
+ ```
197
+
198
+ **Controls** - Control animations programmatically:
199
+
200
+ ```tsx
201
+ const [value, setValue, controls] = useValue(0);
202
+
203
+ // Start animation
204
+ setValue(withSpring(100));
205
+
206
+ // Control playback
207
+ controls.pause();
208
+ controls.resume();
209
+ controls.cancel();
210
+ controls.reset();
211
+ ```
212
+
213
+ ### 3. Animation Descriptors
214
+
215
+ Animation descriptors define how animations behave. They can be used with both `animate` components and `useValue`.
216
+
217
+ #### withSpring
218
+
219
+ Creates physics-based spring animations:
220
+
221
+ ```tsx
222
+ withSpring(100, {
223
+ stiffness: 100, // Spring stiffness (default: 100)
224
+ damping: 15, // Spring damping (default: 15)
225
+ mass: 1, // Spring mass (default: 1)
226
+ })
227
+ ```
228
+
229
+ #### withTiming
230
+
231
+ Creates time-based animations with easing:
232
+
233
+ ```tsx
234
+ withTiming(100, {
235
+ duration: 500, // Duration in milliseconds
236
+ easing: Easing.easeInOut, // Easing function
237
+ })
238
+ ```
239
+
240
+ #### withDecay
241
+
242
+ Creates momentum-based decay animations:
243
+
244
+ ```tsx
245
+ withDecay({
246
+ velocity: 100, // Initial velocity
247
+ clamp: [0, 500], // Optional: clamp values
248
+ })
249
+ ```
250
+
251
+ #### withSequence
252
+
253
+ Runs animations one after another:
254
+
255
+ ```tsx
256
+ withSequence([
257
+ withTiming(100, { duration: 300 }),
258
+ withTiming(200, { duration: 300 }),
259
+ withSpring(0, { stiffness: 200 }),
260
+ ])
261
+ ```
262
+
263
+ #### withLoop
264
+
265
+ Repeats animations:
266
+
267
+ ```tsx
268
+ withLoop(
269
+ withSequence([
270
+ withTiming(90, { duration: 500 }),
271
+ withTiming(180, { duration: 500 }),
272
+ withTiming(360, { duration: 500 }),
273
+ ]),
274
+ 3 // Number of iterations (0 = infinite)
275
+ )
276
+ ```
277
+
278
+ #### withDelay
279
+
280
+ Adds delay to animations (typically used inside `withSequence`):
281
+
282
+ ```tsx
283
+ withSequence([
284
+ withDelay(500),
285
+ withTiming(1, { duration: 500 }),
286
+ ])
287
+ ```
288
+
289
+ ### 4. Animation Recipes
290
+
291
+ Pre-built animation recipes for common use cases:
292
+
293
+ ```tsx
294
+ import {
295
+ animate,
296
+ fadeIn,
297
+ slideInUp,
298
+ scaleIn,
299
+ bounceIn,
300
+ hoverScale,
301
+ pressScale,
302
+ } from 'react-ui-animate';
303
+
304
+ // Enter animations
305
+ <animate.div animate={fadeIn}>Fades in</animate.div>
306
+ <animate.div animate={slideInUp}>Slides up</animate.div>
307
+ <animate.div animate={scaleIn}>Scales in</animate.div>
308
+ <animate.div animate={bounceIn}>Bounces in</animate.div>
309
+
310
+ // State animations
311
+ <animate.button hover={hoverScale} press={pressScale}>
312
+ Interactive Button
313
+ </animate.button>
314
+
315
+ // Exit animations
316
+ <animate.div exit={exitFade}>Fades out</animate.div>
317
+ ```
318
+
319
+ **Available Recipes:**
320
+
321
+ - **Fade**: `fadeIn`, `fadeOut`, `fadeInUp`, `fadeInDown`, `fadeInLeft`, `fadeInRight`
322
+ - **Slide**: `slideInUp`, `slideInDown`, `slideInLeft`, `slideInRight`, `slideOutUp`, `slideOutDown`, `slideOutLeft`, `slideOutRight`
323
+ - **Scale**: `scaleIn`, `scaleOut`, `scaleUp`, `scaleDown`
324
+ - **Bounce**: `bounceIn`, `bounceOut`
325
+ - **Rotate**: `rotateIn`, `rotateOut`, `spin`
326
+ - **Zoom**: `zoomIn`, `zoomOut`
327
+ - **Flip**: `flipX`, `flipY`
328
+ - **Combined**: `slideFadeIn`, `slideFadeOut`, `scaleFadeIn`, `scaleFadeOut`
329
+ - **Hover**: `hoverScale`, `hoverLift`, `hoverGlow`
330
+ - **Press**: `pressScale`, `pressDown`
331
+ - **Exit**: `exitFade`, `exitSlideUp`, `exitSlideDown`, `exitScale`
332
+
333
+ ### 5. Presence Component
334
+
335
+ `Presence` manages mount and unmount animations for components:
336
+
337
+ ```tsx
338
+ import { Presence, animate, withSpring } from 'react-ui-animate';
339
+
340
+ function List() {
341
+ const [items, setItems] = useState(['Item 1', 'Item 2']);
342
+
343
+ return (
344
+ <Presence mode="sync" onExitComplete={() => console.log('All exited')}>
345
+ {items.map((item) => (
346
+ <animate.div
347
+ key={item}
348
+ animate={{ opacity: withSpring(1) }}
349
+ exit={{ opacity: withSpring(0) }}
350
+ >
351
+ {item}
352
+ </animate.div>
353
+ ))}
354
+ </Presence>
355
+ );
356
+ }
357
+ ```
358
+
359
+ **Presence Props:**
360
+
361
+ - `mode`: `'sync'` (default) | `'wait'` | `'popLayout'`
362
+ - `sync`: Exiting and entering animate simultaneously
363
+ - `wait`: Exiting complete before entering start
364
+ - `popLayout`: Exiting removed from layout immediately
365
+ - `initial`: Skip enter animation on initial mount (default: `true`)
366
+ - `onExitComplete`: Callback when all exits complete
367
+
368
+ **Presence Hooks:**
369
+
370
+ ```tsx
371
+ import { usePresence, useIsPresent } from 'react-ui-animate';
372
+
373
+ function AnimatedItem() {
374
+ const [isPresent, onExitComplete] = usePresence();
375
+ const isPresent2 = useIsPresent(); // Simple boolean check
376
+
377
+ // Use isPresent to conditionally render or animate
378
+ return isPresent ? <div>Content</div> : null;
379
+ }
380
+ ```
381
+
382
+ ### 6. Gestures
383
+
384
+ React to user gestures with built-in hooks:
385
+
386
+ #### useDrag
387
+
388
+ Handle drag gestures:
389
+
390
+ ```tsx
391
+ import { useValue, animate, useDrag, withSpring } from 'react-ui-animate';
392
+
393
+ function Draggable() {
394
+ const ref = useRef(null);
395
+ const [x, setX] = useValue(0);
396
+ const [y, setY] = useValue(0);
397
+
398
+ useDrag(ref, ({ down, movement }) => {
399
+ if (down) {
400
+ setX(movement.x);
401
+ setY(movement.y);
402
+ } else {
403
+ setX(withSpring(0));
404
+ setY(withSpring(0));
405
+ }
406
+ });
407
+
408
+ return (
409
+ <animate.div
410
+ ref={ref}
411
+ style={{
412
+ width: 100,
413
+ height: 100,
414
+ backgroundColor: 'blue',
415
+ translateX: x,
416
+ translateY: y,
417
+ }}
418
+ />
419
+ );
420
+ }
421
+ ```
422
+
423
+ #### useMove
424
+
425
+ Track pointer movement:
426
+
427
+ ```tsx
428
+ import { useMove } from 'react-ui-animate';
429
+
430
+ useMove(ref, ({ movement }) => {
431
+ console.log('Moving:', movement.x, movement.y);
432
+ });
433
+ ```
434
+
435
+ #### useScroll
436
+
437
+ React to scroll events:
438
+
439
+ ```tsx
440
+ import { useScroll } from 'react-ui-animate';
441
+
442
+ useScroll(ref, ({ scroll }) => {
443
+ console.log('Scrolled:', scroll.x, scroll.y);
444
+ });
445
+ ```
446
+
447
+ #### useWheel
448
+
449
+ Handle wheel events:
450
+
451
+ ```tsx
452
+ import { useWheel } from 'react-ui-animate';
453
+
454
+ useWheel(ref, ({ delta }) => {
455
+ console.log('Wheel delta:', delta.x, delta.y);
456
+ });
457
+ ```
458
+
459
+ #### useScrollProgress
460
+
461
+ Track scroll progress:
462
+
463
+ ```tsx
464
+ import { useScrollProgress } from 'react-ui-animate';
465
+
466
+ const progress = useScrollProgress(ref, {
467
+ start: 0, // Start tracking at 0% scroll
468
+ end: 100, // End tracking at 100% scroll
469
+ axis: 'y', // 'x' or 'y'
470
+ });
471
+ ```
472
+
473
+ ### 7. Utilities
474
+
475
+ #### makeAnimated
476
+
477
+ Create custom animated components:
478
+
479
+ ```tsx
480
+ import { makeAnimated } from 'react-ui-animate';
481
+
482
+ const AnimatedButton = makeAnimated('button');
483
+ const AnimatedSection = makeAnimated('section');
484
+
485
+ <AnimatedButton animate={{ scale: withSpring(1.1) }}>
486
+ Custom Button
487
+ </AnimatedButton>
488
+ ```
489
+
490
+ #### to (Interpolation)
491
+
492
+ Map values between ranges:
493
+
494
+ ```tsx
495
+ import { to } from 'react-ui-animate';
496
+
497
+ const interpolate = to([0, 100], [0, 500]);
498
+ interpolate(50); // Returns 250
499
+
500
+ // Color interpolation
501
+ const colorInterpolate = to([0, 1], ['red', 'blue']);
502
+ colorInterpolate(0.5); // Returns interpolated color
503
+ ```
504
+
505
+ #### combine
506
+
507
+ Combine multiple animated values:
508
+
509
+ ```tsx
510
+ import { combine, useValue } from 'react-ui-animate';
511
+
512
+ const [x, setX] = useValue(0);
513
+ const [y, setY] = useValue(0);
514
+ const combined = combine(x, y, (x, y) => x + y);
515
+ ```
516
+
517
+ ### 8. Additional Hooks
518
+
519
+ #### useInView
520
+
521
+ Detect when elements enter the viewport:
522
+
523
+ ```tsx
524
+ import { useInView } from 'react-ui-animate';
525
+
526
+ const ref = useRef(null);
527
+ const isInView = useInView(ref, {
528
+ threshold: 0.5,
529
+ once: true,
530
+ });
531
+ ```
532
+
533
+ #### useOutsideClick
534
+
535
+ Detect clicks outside an element:
536
+
537
+ ```tsx
538
+ import { useOutsideClick } from 'react-ui-animate';
539
+
540
+ const ref = useRef(null);
541
+ useOutsideClick(ref, () => {
542
+ console.log('Clicked outside!');
543
+ });
544
+ ```
545
+
546
+ ---
547
+
548
+ ## Complete Examples
549
+
550
+ ### Modal with Exit Animation
551
+
552
+ ```tsx
553
+ import { useState, useRef } from 'react';
554
+ import {
555
+ Presence,
556
+ animate,
557
+ useOutsideClick,
558
+ withSpring,
559
+ withTiming,
560
+ } from 'react-ui-animate';
561
+
562
+ function Modal({ isOpen, onClose }) {
563
+ const ref = useRef(null);
564
+ useOutsideClick(ref, onClose);
565
+
566
+ return (
567
+ <Presence>
568
+ {isOpen && (
569
+ <>
570
+ {/* Backdrop */}
571
+ <animate.div
572
+ key="backdrop"
573
+ style={{
574
+ position: 'fixed',
575
+ inset: 0,
576
+ backgroundColor: 'rgba(0,0,0,0)',
577
+ opacity: 0,
578
+ }}
579
+ animate={{
580
+ backgroundColor: withTiming('rgba(0,0,0,0.5)'),
581
+ opacity: withTiming(1),
582
+ }}
583
+ exit={{
584
+ backgroundColor: withTiming('rgba(0,0,0,0)'),
585
+ opacity: withTiming(0),
586
+ }}
587
+ />
588
+
589
+ {/* Modal */}
590
+ <animate.div
591
+ key="modal"
592
+ ref={ref}
593
+ style={{
594
+ position: 'fixed',
595
+ inset: 0,
596
+ display: 'flex',
597
+ alignItems: 'center',
598
+ justifyContent: 'center',
599
+ scale: 0.8,
600
+ opacity: 0,
601
+ }}
602
+ animate={{
603
+ scale: withSpring(1),
604
+ opacity: withSpring(1),
605
+ }}
606
+ exit={{
607
+ scale: withSpring(0.8),
608
+ opacity: withSpring(0),
609
+ }}
610
+ >
611
+ <div style={{ backgroundColor: 'white', padding: 20 }}>
612
+ Modal Content
613
+ </div>
614
+ </animate.div>
615
+ </>
616
+ )}
617
+ </Presence>
618
+ );
619
+ }
620
+ ```
621
+
622
+ ### Scroll-Triggered Animations
623
+
624
+ ```tsx
625
+ import { animate, withSpring, withTiming } from 'react-ui-animate';
626
+
627
+ function FeatureCard({ title, description }) {
628
+ return (
629
+ <animate.div
630
+ style={{
631
+ opacity: 0,
632
+ translateY: 50,
633
+ scale: 0.9,
634
+ }}
635
+ view={{
636
+ opacity: withTiming(1, { duration: 600 }),
637
+ translateY: withSpring(0),
638
+ scale: withSpring(1),
639
+ }}
640
+ viewOptions={{ threshold: 0.3, once: true }}
641
+ >
642
+ <h3>{title}</h3>
643
+ <p>{description}</p>
644
+ </animate.div>
645
+ );
646
+ }
647
+ ```
648
+
649
+ ### Interactive Button
650
+
651
+ ```tsx
652
+ import { animate, withSpring, hoverScale, pressScale } from 'react-ui-animate';
653
+
654
+ <animate.button
655
+ style={{
656
+ padding: '12px 24px',
657
+ backgroundColor: '#3399ff',
658
+ color: 'white',
659
+ border: 'none',
660
+ borderRadius: 8,
661
+ cursor: 'pointer',
662
+ }}
663
+ hover={hoverScale}
664
+ press={pressScale}
665
+ >
666
+ Click Me
667
+ </animate.button>
668
+ ```
669
+
670
+ ---
671
+
672
+ ## API Reference
673
+
674
+ ### Animation Descriptors
675
+
676
+ | Descriptor | Description | Options |
677
+ |------------|-------------|---------|
678
+ | `withSpring(to, options?)` | Physics-based spring | `stiffness`, `damping`, `mass`, `from`, callbacks |
679
+ | `withTiming(to, options?)` | Time-based animation | `duration`, `easing`, `from`, callbacks |
680
+ | `withDecay(options)` | Momentum decay | `velocity`, `clamp`, callbacks |
681
+ | `withSequence(animations)` | Run sequentially | `animations` array, callbacks |
682
+ | `withLoop(animation, iterations)` | Repeat animation | `iterations` (0 = infinite), callbacks |
683
+ | `withDelay(ms)` | Add delay | `delay` in milliseconds |
684
+
685
+ ### Animate Component Props
686
+
687
+ | Prop | Type | Description |
688
+ |------|------|-------------|
689
+ | `animate` | `AnimateProp` | Animations on mount/update |
690
+ | `exit` | `AnimateProp` | Animations on unmount (requires `Presence`) |
691
+ | `hover` | `AnimateProp` | Animations on hover |
692
+ | `press` | `AnimateProp` | Animations on press (mousedown/touchstart) |
693
+ | `focus` | `AnimateProp` | Animations on focus |
694
+ | `view` | `AnimateProp` | Animations when entering viewport |
695
+ | `viewOptions` | `UseInViewOptions` | IntersectionObserver options |
696
+
697
+ ### Callbacks
698
+
699
+ All descriptors support optional callbacks:
700
+
701
+ ```tsx
702
+ withSpring(100, {
703
+ onStart: () => console.log('Started'),
704
+ onChange: (value) => console.log('Value:', value),
705
+ onComplete: () => console.log('Completed'),
706
+ })
707
+ ```
708
+
709
+ ---
710
+
711
+ ## TypeScript Support
712
+
713
+ Full TypeScript support is included. All components, hooks, and utilities are fully typed.
714
+
715
+ ---
716
+
717
+ ## Performance
718
+
719
+ - Animations run on the GPU when possible
720
+ - Automatic batching of style updates
721
+ - Optimized re-renders
722
+ - Tree-shakeable exports
723
+
724
+ ---
725
+
726
+ ## Browser Support
727
+
728
+ - Chrome/Edge (latest)
729
+ - Firefox (latest)
730
+ - Safari (latest)
731
+ - Mobile browsers (iOS Safari, Chrome Mobile)
732
+
733
+ ---
734
+
735
+ ## Documentation
736
+
737
+ For detailed documentation and more examples, visit the [official documentation](https://react-ui-animate.js.org/).
738
+
739
+ ---
740
+
741
+ ## License
742
+
743
+ MIT © [Dipesh Rai](https://github.com/dipeshrai123)