react-native-ultra-carousel 0.1.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/package.json +81 -0
- package/src/animations/basic/fade.ts +51 -0
- package/src/animations/basic/overlap.ts +69 -0
- package/src/animations/basic/parallax.ts +65 -0
- package/src/animations/basic/peek.ts +79 -0
- package/src/animations/basic/scale.ts +63 -0
- package/src/animations/basic/scaleFade.ts +73 -0
- package/src/animations/basic/slide.ts +53 -0
- package/src/animations/basic/slideFade.ts +60 -0
- package/src/animations/basic/vertical.ts +50 -0
- package/src/animations/basic/verticalFade.ts +60 -0
- package/src/animations/index.ts +45 -0
- package/src/animations/registry.ts +175 -0
- package/src/animations/types.ts +11 -0
- package/src/animations/utils.ts +75 -0
- package/src/components/AutoPlayController.tsx +38 -0
- package/src/components/Carousel.tsx +371 -0
- package/src/components/CarouselItem.tsx +98 -0
- package/src/components/Pagination/BarPagination.tsx +141 -0
- package/src/components/Pagination/CustomPagination.tsx +48 -0
- package/src/components/Pagination/DotPagination.tsx +137 -0
- package/src/components/Pagination/NumberPagination.tsx +117 -0
- package/src/components/Pagination/Pagination.tsx +82 -0
- package/src/components/Pagination/ProgressPagination.tsx +70 -0
- package/src/components/Pagination/index.ts +11 -0
- package/src/components/ParallaxImage.tsx +89 -0
- package/src/gestures/FlingGestureManager.ts +49 -0
- package/src/gestures/PanGestureManager.ts +202 -0
- package/src/gestures/ScrollViewCompat.ts +28 -0
- package/src/gestures/types.ts +6 -0
- package/src/hooks/useAnimationProgress.ts +33 -0
- package/src/hooks/useAutoPlay.ts +115 -0
- package/src/hooks/useCarousel.ts +118 -0
- package/src/hooks/useCarouselGesture.ts +109 -0
- package/src/hooks/useItemAnimation.ts +44 -0
- package/src/hooks/usePagination.ts +39 -0
- package/src/hooks/useSnapPoints.ts +31 -0
- package/src/hooks/useVirtualization.ts +63 -0
- package/src/index.ts +71 -0
- package/src/plugins/PluginManager.ts +150 -0
- package/src/plugins/types.ts +6 -0
- package/src/types/animation.ts +72 -0
- package/src/types/carousel.ts +188 -0
- package/src/types/gesture.ts +42 -0
- package/src/types/index.ts +41 -0
- package/src/types/pagination.ts +65 -0
- package/src/types/plugin.ts +27 -0
- package/src/utils/accessibility.ts +71 -0
- package/src/utils/constants.ts +45 -0
- package/src/utils/layout.ts +115 -0
- package/src/utils/math.ts +78 -0
- package/src/utils/platform.ts +33 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Vertical-fade animation preset
|
|
3
|
+
* @description Combines vertical slide with opacity fade
|
|
4
|
+
* @preset vertical-fade
|
|
5
|
+
* @difficulty Easy
|
|
6
|
+
* @phase 1
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { interpolate, Extrapolation } from 'react-native-reanimated';
|
|
10
|
+
import type { AnimatedItemStyle } from '../types';
|
|
11
|
+
|
|
12
|
+
/** Configuration for the vertical-fade animation */
|
|
13
|
+
export interface VerticalFadeConfig {
|
|
14
|
+
/** Vertical distance in pixels (default: 200) */
|
|
15
|
+
distance: number;
|
|
16
|
+
/** Minimum opacity for inactive items (default: 0.3) */
|
|
17
|
+
minOpacity: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Default vertical-fade configuration */
|
|
21
|
+
export const VERTICAL_FADE_DEFAULTS: VerticalFadeConfig = {
|
|
22
|
+
distance: 200,
|
|
23
|
+
minOpacity: 0.3,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Vertical-fade animation worklet.
|
|
28
|
+
* Combines vertical translation with opacity reduction.
|
|
29
|
+
*
|
|
30
|
+
* @param progress - Normalized item progress: 0 = active, -1 = prev, +1 = next
|
|
31
|
+
* @param config - Optional overrides for default configuration
|
|
32
|
+
* @returns Animated style to apply to the carousel item
|
|
33
|
+
*/
|
|
34
|
+
export const verticalFadeAnimation = (
|
|
35
|
+
progress: number,
|
|
36
|
+
config?: Partial<VerticalFadeConfig>
|
|
37
|
+
): AnimatedItemStyle => {
|
|
38
|
+
'worklet';
|
|
39
|
+
|
|
40
|
+
const c = { ...VERTICAL_FADE_DEFAULTS, ...config };
|
|
41
|
+
|
|
42
|
+
const translateY = interpolate(
|
|
43
|
+
progress,
|
|
44
|
+
[-1, 0, 1],
|
|
45
|
+
[-c.distance, 0, c.distance],
|
|
46
|
+
Extrapolation.CLAMP
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const opacity = interpolate(
|
|
50
|
+
Math.abs(progress),
|
|
51
|
+
[0, 1],
|
|
52
|
+
[1, c.minOpacity],
|
|
53
|
+
Extrapolation.CLAMP
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
transform: [{ translateY }],
|
|
58
|
+
opacity,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Animation presets public exports
|
|
3
|
+
* @description Export all animation presets and registry utilities
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { slideAnimation, SLIDE_DEFAULTS } from './basic/slide';
|
|
7
|
+
export type { SlideConfig } from './basic/slide';
|
|
8
|
+
|
|
9
|
+
export { fadeAnimation, FADE_DEFAULTS } from './basic/fade';
|
|
10
|
+
export type { FadeConfig } from './basic/fade';
|
|
11
|
+
|
|
12
|
+
export { slideFadeAnimation, SLIDE_FADE_DEFAULTS } from './basic/slideFade';
|
|
13
|
+
export type { SlideFadeConfig } from './basic/slideFade';
|
|
14
|
+
|
|
15
|
+
export { scaleAnimation, SCALE_DEFAULTS } from './basic/scale';
|
|
16
|
+
export type { ScaleConfig } from './basic/scale';
|
|
17
|
+
|
|
18
|
+
export { scaleFadeAnimation, SCALE_FADE_DEFAULTS } from './basic/scaleFade';
|
|
19
|
+
export type { ScaleFadeConfig } from './basic/scaleFade';
|
|
20
|
+
|
|
21
|
+
export { verticalAnimation, VERTICAL_DEFAULTS } from './basic/vertical';
|
|
22
|
+
export type { VerticalConfig } from './basic/vertical';
|
|
23
|
+
|
|
24
|
+
export { verticalFadeAnimation, VERTICAL_FADE_DEFAULTS } from './basic/verticalFade';
|
|
25
|
+
export type { VerticalFadeConfig } from './basic/verticalFade';
|
|
26
|
+
|
|
27
|
+
export { parallaxAnimation, PARALLAX_DEFAULTS } from './basic/parallax';
|
|
28
|
+
export type { ParallaxConfig } from './basic/parallax';
|
|
29
|
+
|
|
30
|
+
export { overlapAnimation, OVERLAP_DEFAULTS } from './basic/overlap';
|
|
31
|
+
export type { OverlapConfig } from './basic/overlap';
|
|
32
|
+
|
|
33
|
+
export { peekAnimation, PEEK_DEFAULTS } from './basic/peek';
|
|
34
|
+
export type { PeekConfig } from './basic/peek';
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
registerPreset,
|
|
38
|
+
getPreset,
|
|
39
|
+
getPresetMeta,
|
|
40
|
+
getAllPresetNames,
|
|
41
|
+
getAllPresetMeta,
|
|
42
|
+
isPresetRegistered,
|
|
43
|
+
} from './registry';
|
|
44
|
+
|
|
45
|
+
export type { AnimatedItemStyle, AnimationPresetFn, AnimationPresetMeta } from './types';
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Animation preset registry
|
|
3
|
+
* @description Central registry for all animation presets — lookup by name
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { AnimationPresetFn, AnimationPresetMeta } from './types';
|
|
7
|
+
import { slideAnimation } from './basic/slide';
|
|
8
|
+
import { fadeAnimation } from './basic/fade';
|
|
9
|
+
import { slideFadeAnimation } from './basic/slideFade';
|
|
10
|
+
import { scaleAnimation } from './basic/scale';
|
|
11
|
+
import { scaleFadeAnimation } from './basic/scaleFade';
|
|
12
|
+
import { verticalAnimation } from './basic/vertical';
|
|
13
|
+
import { verticalFadeAnimation } from './basic/verticalFade';
|
|
14
|
+
import { parallaxAnimation } from './basic/parallax';
|
|
15
|
+
import { overlapAnimation } from './basic/overlap';
|
|
16
|
+
import { peekAnimation } from './basic/peek';
|
|
17
|
+
|
|
18
|
+
/** Internal registry map of preset names to animation functions */
|
|
19
|
+
const registry = new Map<string, AnimationPresetFn>();
|
|
20
|
+
|
|
21
|
+
/** Internal metadata registry */
|
|
22
|
+
const metaRegistry = new Map<string, AnimationPresetMeta>();
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Registers a preset in the animation registry.
|
|
26
|
+
*
|
|
27
|
+
* @param meta - Full metadata for the preset including the animation function
|
|
28
|
+
*/
|
|
29
|
+
export const registerPreset = (meta: AnimationPresetMeta): void => {
|
|
30
|
+
registry.set(meta.name, meta.animation);
|
|
31
|
+
metaRegistry.set(meta.name, meta);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Retrieves an animation function by preset name.
|
|
36
|
+
*
|
|
37
|
+
* @param name - The preset name to look up
|
|
38
|
+
* @returns The animation function, or undefined if not found
|
|
39
|
+
*/
|
|
40
|
+
export const getPreset = (name: string): AnimationPresetFn | undefined => {
|
|
41
|
+
return registry.get(name);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Retrieves metadata for a preset by name.
|
|
46
|
+
*
|
|
47
|
+
* @param name - The preset name to look up
|
|
48
|
+
* @returns The preset metadata, or undefined if not found
|
|
49
|
+
*/
|
|
50
|
+
export const getPresetMeta = (name: string): AnimationPresetMeta | undefined => {
|
|
51
|
+
return metaRegistry.get(name);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns all registered preset names.
|
|
56
|
+
*
|
|
57
|
+
* @returns Array of registered preset names
|
|
58
|
+
*/
|
|
59
|
+
export const getAllPresetNames = (): string[] => {
|
|
60
|
+
return Array.from(registry.keys());
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Returns all registered preset metadata.
|
|
65
|
+
*
|
|
66
|
+
* @returns Array of all preset metadata
|
|
67
|
+
*/
|
|
68
|
+
export const getAllPresetMeta = (): AnimationPresetMeta[] => {
|
|
69
|
+
return Array.from(metaRegistry.values());
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Checks whether a preset name is registered.
|
|
74
|
+
*
|
|
75
|
+
* @param name - The preset name to check
|
|
76
|
+
* @returns True if the preset is registered
|
|
77
|
+
*/
|
|
78
|
+
export const isPresetRegistered = (name: string): boolean => {
|
|
79
|
+
return registry.has(name);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** Register all built-in basic presets */
|
|
83
|
+
const registerBuiltInPresets = (): void => {
|
|
84
|
+
registerPreset({
|
|
85
|
+
name: 'slide',
|
|
86
|
+
description: 'Standard horizontal slide transition',
|
|
87
|
+
difficulty: 'Easy',
|
|
88
|
+
phase: 1,
|
|
89
|
+
animation: slideAnimation,
|
|
90
|
+
defaults: { distance: 1 },
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
registerPreset({
|
|
94
|
+
name: 'fade',
|
|
95
|
+
description: 'Crossfade transition between stacked items',
|
|
96
|
+
difficulty: 'Easy',
|
|
97
|
+
phase: 1,
|
|
98
|
+
animation: fadeAnimation,
|
|
99
|
+
defaults: { minOpacity: 0 },
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
registerPreset({
|
|
103
|
+
name: 'slide-fade',
|
|
104
|
+
description: 'Horizontal slide combined with opacity fade',
|
|
105
|
+
difficulty: 'Easy',
|
|
106
|
+
phase: 1,
|
|
107
|
+
animation: slideFadeAnimation,
|
|
108
|
+
defaults: { distance: 200, minOpacity: 0.3 },
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
registerPreset({
|
|
112
|
+
name: 'scale',
|
|
113
|
+
description: 'Active item full size, neighbors scale down',
|
|
114
|
+
difficulty: 'Easy',
|
|
115
|
+
phase: 1,
|
|
116
|
+
animation: scaleAnimation,
|
|
117
|
+
defaults: { minScale: 0.8, spacing: 50 },
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
registerPreset({
|
|
121
|
+
name: 'scale-fade',
|
|
122
|
+
description: 'Scale reduction combined with opacity fade',
|
|
123
|
+
difficulty: 'Easy',
|
|
124
|
+
phase: 1,
|
|
125
|
+
animation: scaleFadeAnimation,
|
|
126
|
+
defaults: { minScale: 0.85, minOpacity: 0.5, spacing: 40 },
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
registerPreset({
|
|
130
|
+
name: 'vertical',
|
|
131
|
+
description: 'Vertical slide transition',
|
|
132
|
+
difficulty: 'Easy',
|
|
133
|
+
phase: 1,
|
|
134
|
+
animation: verticalAnimation,
|
|
135
|
+
defaults: { distance: 250 },
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
registerPreset({
|
|
139
|
+
name: 'vertical-fade',
|
|
140
|
+
description: 'Vertical slide combined with opacity fade',
|
|
141
|
+
difficulty: 'Easy',
|
|
142
|
+
phase: 1,
|
|
143
|
+
animation: verticalFadeAnimation,
|
|
144
|
+
defaults: { distance: 200, minOpacity: 0.3 },
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
registerPreset({
|
|
148
|
+
name: 'parallax',
|
|
149
|
+
description: 'Multi-layer parallax depth effect',
|
|
150
|
+
difficulty: 'Medium',
|
|
151
|
+
phase: 1,
|
|
152
|
+
animation: parallaxAnimation,
|
|
153
|
+
defaults: { parallaxFactor: 0.3, distance: 300, minOpacity: 0.8 },
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
registerPreset({
|
|
157
|
+
name: 'overlap',
|
|
158
|
+
description: 'Items overlap each other with stacked appearance',
|
|
159
|
+
difficulty: 'Medium',
|
|
160
|
+
phase: 1,
|
|
161
|
+
animation: overlapAnimation,
|
|
162
|
+
defaults: { overlapRatio: 0.7, minScale: 0.95, itemWidth: 300 },
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
registerPreset({
|
|
166
|
+
name: 'peek',
|
|
167
|
+
description: 'Active item centered with adjacent items peeking from sides',
|
|
168
|
+
difficulty: 'Medium',
|
|
169
|
+
phase: 1,
|
|
170
|
+
animation: peekAnimation,
|
|
171
|
+
defaults: { peekAmount: 0.2, peekScale: 0.85, peekOpacity: 0.7, itemWidth: 300 },
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
registerBuiltInPresets();
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Shared animation utility functions
|
|
3
|
+
* @description Common helpers used across animation presets
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { interpolate, Extrapolation } from 'react-native-reanimated';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Symmetric interpolation helper for common animation patterns.
|
|
10
|
+
* Maps progress [-1, 0, 1] to [edge, center, edge] values.
|
|
11
|
+
*
|
|
12
|
+
* @param progress - Normalized progress value
|
|
13
|
+
* @param center - Value at progress = 0 (active)
|
|
14
|
+
* @param edge - Value at progress = -1 or 1
|
|
15
|
+
* @returns Interpolated value
|
|
16
|
+
*/
|
|
17
|
+
export const symmetricInterpolate = (
|
|
18
|
+
progress: number,
|
|
19
|
+
center: number,
|
|
20
|
+
edge: number
|
|
21
|
+
): number => {
|
|
22
|
+
'worklet';
|
|
23
|
+
return interpolate(
|
|
24
|
+
progress,
|
|
25
|
+
[-1, 0, 1],
|
|
26
|
+
[edge, center, edge],
|
|
27
|
+
Extrapolation.CLAMP
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Directional interpolation for left-center-right patterns.
|
|
33
|
+
*
|
|
34
|
+
* @param progress - Normalized progress value
|
|
35
|
+
* @param left - Value at progress = -1
|
|
36
|
+
* @param center - Value at progress = 0
|
|
37
|
+
* @param right - Value at progress = 1
|
|
38
|
+
* @returns Interpolated value
|
|
39
|
+
*/
|
|
40
|
+
export const directionalInterpolate = (
|
|
41
|
+
progress: number,
|
|
42
|
+
left: number,
|
|
43
|
+
center: number,
|
|
44
|
+
right: number
|
|
45
|
+
): number => {
|
|
46
|
+
'worklet';
|
|
47
|
+
return interpolate(
|
|
48
|
+
progress,
|
|
49
|
+
[-1, 0, 1],
|
|
50
|
+
[left, center, right],
|
|
51
|
+
Extrapolation.CLAMP
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Computes zIndex based on distance from active item.
|
|
57
|
+
* Active item gets highest zIndex.
|
|
58
|
+
*
|
|
59
|
+
* @param progress - Normalized progress value
|
|
60
|
+
* @param maxZIndex - Maximum zIndex for active item
|
|
61
|
+
* @returns Rounded zIndex value
|
|
62
|
+
*/
|
|
63
|
+
export const computeZIndex = (
|
|
64
|
+
progress: number,
|
|
65
|
+
maxZIndex: number = 100
|
|
66
|
+
): number => {
|
|
67
|
+
'worklet';
|
|
68
|
+
const z = interpolate(
|
|
69
|
+
Math.abs(progress),
|
|
70
|
+
[0, 1],
|
|
71
|
+
[maxZIndex, 0],
|
|
72
|
+
Extrapolation.CLAMP
|
|
73
|
+
);
|
|
74
|
+
return Math.round(z);
|
|
75
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file AutoPlayController component
|
|
3
|
+
* @description Headless component that manages auto play lifecycle
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useEffect } from 'react';
|
|
7
|
+
import type { AutoPlayConfig } from '../types';
|
|
8
|
+
import { useAutoPlay, type UseAutoPlayReturn } from '../hooks/useAutoPlay';
|
|
9
|
+
|
|
10
|
+
/** Props for the AutoPlayController */
|
|
11
|
+
export interface AutoPlayControllerProps {
|
|
12
|
+
/** Auto play configuration */
|
|
13
|
+
config: AutoPlayConfig | boolean | undefined;
|
|
14
|
+
/** Callback to advance carousel */
|
|
15
|
+
onAdvance: (direction: 'forward' | 'backward') => void;
|
|
16
|
+
/** Callback to expose auto play controls to parent */
|
|
17
|
+
onControlsReady?: (controls: UseAutoPlayReturn) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Headless component that manages carousel auto play.
|
|
22
|
+
* Renders nothing — all logic is in hooks.
|
|
23
|
+
*/
|
|
24
|
+
export const AutoPlayController: React.FC<AutoPlayControllerProps> = ({
|
|
25
|
+
config,
|
|
26
|
+
onAdvance,
|
|
27
|
+
onControlsReady,
|
|
28
|
+
}) => {
|
|
29
|
+
const controls = useAutoPlay(config, onAdvance);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
onControlsReady?.(controls);
|
|
33
|
+
}, [controls, onControlsReady]);
|
|
34
|
+
|
|
35
|
+
return null;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
AutoPlayController.displayName = 'AutoPlayController';
|