@umituz/react-native-design-system 2.6.47 → 2.6.49
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 +1 -1
- package/src/atoms/skeleton/AtomicSkeleton.tsx +16 -62
- package/src/index.ts +0 -32
- package/src/molecules/bottom-sheet/components/BottomSheetModal.tsx +101 -180
- package/src/molecules/bottom-sheet/components/SafeBottomSheetModalProvider.tsx +8 -14
- package/src/molecules/index.ts +0 -6
- package/src/molecules/animation/core/AnimationCore.ts +0 -29
- package/src/molecules/animation/domain/entities/Animation.ts +0 -81
- package/src/molecules/animation/domain/entities/Fireworks.ts +0 -44
- package/src/molecules/animation/domain/entities/Theme.ts +0 -76
- package/src/molecules/animation/index.ts +0 -146
- package/src/molecules/animation/infrastructure/services/AnimationConfigService.ts +0 -35
- package/src/molecules/animation/infrastructure/services/SpringAnimationConfigService.ts +0 -67
- package/src/molecules/animation/infrastructure/services/TimingAnimationConfigService.ts +0 -57
- package/src/molecules/animation/infrastructure/services/__tests__/SpringAnimationConfigService.test.ts +0 -114
- package/src/molecules/animation/infrastructure/services/__tests__/TimingAnimationConfigService.test.ts +0 -105
- package/src/molecules/animation/presentation/components/Fireworks.tsx +0 -127
- package/src/molecules/animation/presentation/components/__tests__/Fireworks.test.tsx +0 -185
- package/src/molecules/animation/presentation/hooks/__tests__/useAnimation.integration.test.ts +0 -210
- package/src/molecules/animation/presentation/hooks/__tests__/useFireworks.test.ts +0 -242
- package/src/molecules/animation/presentation/hooks/__tests__/useGesture.test.ts +0 -108
- package/src/molecules/animation/presentation/hooks/__tests__/useSpringAnimation.test.ts +0 -127
- package/src/molecules/animation/presentation/hooks/__tests__/useTimingAnimation.test.ts +0 -172
- package/src/molecules/animation/presentation/hooks/__tests__/useTransformAnimation.test.ts +0 -133
- package/src/molecules/animation/presentation/hooks/useAnimation.ts +0 -77
- package/src/molecules/animation/presentation/hooks/useFireworks.ts +0 -144
- package/src/molecules/animation/presentation/hooks/useGesture.ts +0 -57
- package/src/molecules/animation/presentation/hooks/useGestureCreators.ts +0 -163
- package/src/molecules/animation/presentation/hooks/useGestureState.ts +0 -53
- package/src/molecules/animation/presentation/hooks/useIconAnimations.ts +0 -120
- package/src/molecules/animation/presentation/hooks/useModalAnimations.ts +0 -124
- package/src/molecules/animation/presentation/hooks/useReanimatedReady.ts +0 -60
- package/src/molecules/animation/presentation/hooks/useSpringAnimation.ts +0 -69
- package/src/molecules/animation/presentation/hooks/useTimingAnimation.ts +0 -111
- package/src/molecules/animation/presentation/hooks/useTransformAnimation.ts +0 -57
- package/src/molecules/animation/presentation/providers/AnimationThemeProvider.tsx +0 -60
- package/src/molecules/animation/presentation/providers/__tests__/AnimationThemeProvider.test.tsx +0 -165
- package/src/molecules/celebration/domain/entities/CelebrationConfig.ts +0 -17
- package/src/molecules/celebration/domain/entities/FireworksConfig.ts +0 -32
- package/src/molecules/celebration/index.ts +0 -93
- package/src/molecules/celebration/infrastructure/services/FireworksConfigService.ts +0 -49
- package/src/molecules/celebration/presentation/components/CelebrationFireworksOverlay.tsx +0 -33
- package/src/molecules/celebration/presentation/components/CelebrationModal.tsx +0 -81
- package/src/molecules/celebration/presentation/components/CelebrationModalContent.tsx +0 -88
- package/src/molecules/celebration/presentation/hooks/useCelebrationModalAnimation.ts +0 -49
- package/src/molecules/celebration/presentation/hooks/useCelebrationState.ts +0 -45
- package/src/molecules/celebration/presentation/styles/CelebrationModalStyles.ts +0 -65
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useTransformAnimation Hook Tests
|
|
3
|
-
*
|
|
4
|
-
* Unit tests for transform-based animations (spin, pulse, shake).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { renderHook, act } from '@testing-library/react';
|
|
8
|
-
import { useTransformAnimation } from '../useTransformAnimation';
|
|
9
|
-
import { withTiming, withSequence, withRepeat, Easing } from 'react-native-reanimated';
|
|
10
|
-
|
|
11
|
-
// Mock react-native-reanimated
|
|
12
|
-
jest.mock('react-native-reanimated', () => ({
|
|
13
|
-
useSharedValue: jest.fn((initialValue) => ({
|
|
14
|
-
value: initialValue,
|
|
15
|
-
})),
|
|
16
|
-
useAnimatedStyle: jest.fn((styleFactory) => styleFactory()),
|
|
17
|
-
withTiming: jest.fn((toValue, config) => ({ toValue, config })),
|
|
18
|
-
withSequence: jest.fn((...animations) => animations),
|
|
19
|
-
withRepeat: jest.fn((animation, count, reverse) => ({ animation, count, reverse })),
|
|
20
|
-
Easing: {
|
|
21
|
-
linear: jest.fn(),
|
|
22
|
-
},
|
|
23
|
-
}));
|
|
24
|
-
|
|
25
|
-
describe('useTransformAnimation', () => {
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
jest.clearAllMocks();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should initialize with default values', () => {
|
|
31
|
-
const { result } = renderHook(() => useTransformAnimation());
|
|
32
|
-
|
|
33
|
-
expect(result.current.translateX.value).toBe(0);
|
|
34
|
-
expect(result.current.scale.value).toBe(1);
|
|
35
|
-
expect(result.current.rotate.value).toBe(0);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should provide animation functions', () => {
|
|
39
|
-
const { result } = renderHook(() => useTransformAnimation());
|
|
40
|
-
|
|
41
|
-
expect(typeof result.current.shake).toBe('function');
|
|
42
|
-
expect(typeof result.current.pulse).toBe('function');
|
|
43
|
-
expect(typeof result.current.spin).toBe('function');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe('shake', () => {
|
|
47
|
-
it('should create shake animation sequence', () => {
|
|
48
|
-
const { result } = renderHook(() => useTransformAnimation());
|
|
49
|
-
|
|
50
|
-
act(() => {
|
|
51
|
-
result.current.shake();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
expect(withSequence).toHaveBeenCalledWith(
|
|
55
|
-
withTiming(-10, { duration: 50 }),
|
|
56
|
-
withRepeat(withTiming(10, { duration: 50 }), 4, true),
|
|
57
|
-
withTiming(0, { duration: 50 })
|
|
58
|
-
);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe('pulse', () => {
|
|
63
|
-
it('should create pulse animation with default repeat count', () => {
|
|
64
|
-
const { result } = renderHook(() => useTransformAnimation());
|
|
65
|
-
|
|
66
|
-
act(() => {
|
|
67
|
-
result.current.pulse();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
expect(withRepeat).toHaveBeenCalledWith(
|
|
71
|
-
withSequence(withTiming(1.1, { duration: 500 }), withTiming(1, { duration: 500 })),
|
|
72
|
-
-1,
|
|
73
|
-
false
|
|
74
|
-
);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should use custom repeat count', () => {
|
|
78
|
-
const { result } = renderHook(() => useTransformAnimation());
|
|
79
|
-
const customRepeatCount = 3;
|
|
80
|
-
|
|
81
|
-
act(() => {
|
|
82
|
-
result.current.pulse(customRepeatCount);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
expect(withRepeat).toHaveBeenCalledWith(
|
|
86
|
-
expect.any(Object),
|
|
87
|
-
customRepeatCount,
|
|
88
|
-
false
|
|
89
|
-
);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
describe('spin', () => {
|
|
94
|
-
it('should create spin animation with default repeat count', () => {
|
|
95
|
-
const { result } = renderHook(() => useTransformAnimation());
|
|
96
|
-
|
|
97
|
-
act(() => {
|
|
98
|
-
result.current.spin();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
expect(withRepeat).toHaveBeenCalledWith(
|
|
102
|
-
withTiming(360, { duration: 1000, easing: Easing.linear }),
|
|
103
|
-
-1,
|
|
104
|
-
false
|
|
105
|
-
);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should use custom repeat count', () => {
|
|
109
|
-
const { result } = renderHook(() => useTransformAnimation());
|
|
110
|
-
const customRepeatCount = 2;
|
|
111
|
-
|
|
112
|
-
act(() => {
|
|
113
|
-
result.current.spin(customRepeatCount);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
expect(withRepeat).toHaveBeenCalledWith(
|
|
117
|
-
expect.any(Object),
|
|
118
|
-
customRepeatCount,
|
|
119
|
-
false
|
|
120
|
-
);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('shared values', () => {
|
|
125
|
-
it('should expose shared values for custom animations', () => {
|
|
126
|
-
const { result } = renderHook(() => useTransformAnimation());
|
|
127
|
-
|
|
128
|
-
expect(result.current.translateX).toBeDefined();
|
|
129
|
-
expect(result.current.scale).toBeDefined();
|
|
130
|
-
expect(result.current.rotate).toBeDefined();
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
});
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useAnimation Hook
|
|
3
|
-
*
|
|
4
|
-
* Orchestrator hook that combines all animation types.
|
|
5
|
-
* Single Responsibility: Compose and expose animation hooks.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { useAnimatedStyle } from 'react-native-reanimated';
|
|
9
|
-
import { useTimingAnimation } from './useTimingAnimation';
|
|
10
|
-
import { useSpringAnimation } from './useSpringAnimation';
|
|
11
|
-
import { useTransformAnimation } from './useTransformAnimation';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Hook for declarative animations
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* const { fadeIn, fadeOut, animatedStyle } = useAnimation();
|
|
18
|
-
*
|
|
19
|
-
* // Trigger animations
|
|
20
|
-
* fadeIn();
|
|
21
|
-
* fadeOut();
|
|
22
|
-
*
|
|
23
|
-
* // Apply to component
|
|
24
|
-
* <Animated.View style={animatedStyle}>...</Animated.View>
|
|
25
|
-
*/
|
|
26
|
-
export const useAnimation = () => {
|
|
27
|
-
const timing = useTimingAnimation();
|
|
28
|
-
const spring = useSpringAnimation();
|
|
29
|
-
const transform = useTransformAnimation();
|
|
30
|
-
|
|
31
|
-
// Combine all shared values for animated style
|
|
32
|
-
const animatedStyle = useAnimatedStyle(() => {
|
|
33
|
-
// Use transform values if they're non-zero, otherwise use timing/spring values
|
|
34
|
-
const translateXValue = transform.translateX.value !== 0
|
|
35
|
-
? transform.translateX.value
|
|
36
|
-
: timing.translateX.value;
|
|
37
|
-
const scaleValue = transform.scale.value !== 1
|
|
38
|
-
? transform.scale.value
|
|
39
|
-
: spring.scale.value;
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
opacity: timing.opacity.value,
|
|
43
|
-
transform: [
|
|
44
|
-
{ translateY: timing.translateY.value },
|
|
45
|
-
{ translateX: translateXValue },
|
|
46
|
-
{ scale: scaleValue },
|
|
47
|
-
{ rotate: `${transform.rotate.value}deg` },
|
|
48
|
-
] as any,
|
|
49
|
-
};
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
// Timing animations
|
|
54
|
-
fadeIn: timing.fadeIn,
|
|
55
|
-
fadeOut: timing.fadeOut,
|
|
56
|
-
slideInUp: timing.slideInUp,
|
|
57
|
-
slideInDown: timing.slideInDown,
|
|
58
|
-
slideInLeft: timing.slideInLeft,
|
|
59
|
-
slideInRight: timing.slideInRight,
|
|
60
|
-
// Spring animations
|
|
61
|
-
scaleIn: spring.scaleIn,
|
|
62
|
-
scaleOut: spring.scaleOut,
|
|
63
|
-
bounce: spring.bounce,
|
|
64
|
-
// Transform animations
|
|
65
|
-
shake: transform.shake,
|
|
66
|
-
pulse: transform.pulse,
|
|
67
|
-
spin: transform.spin,
|
|
68
|
-
// Shared values (for custom animations)
|
|
69
|
-
opacity: timing.opacity,
|
|
70
|
-
translateY: timing.translateY,
|
|
71
|
-
translateX: timing.translateX,
|
|
72
|
-
scale: spring.scale,
|
|
73
|
-
rotate: transform.rotate,
|
|
74
|
-
// Animated style
|
|
75
|
-
animatedStyle,
|
|
76
|
-
};
|
|
77
|
-
};
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useFireworks Hook
|
|
3
|
-
*
|
|
4
|
-
* Hook for managing fireworks particle system.
|
|
5
|
-
* Single Responsibility: Manage fireworks state and lifecycle.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
9
|
-
import type { ParticleConfig, FireworksConfig } from '../../domain/entities/Fireworks';
|
|
10
|
-
import { FIREWORKS_CONSTANTS } from '../../domain/entities/Fireworks';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Hook for fireworks animation
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* const { particles, trigger, isActive } = useFireworks();
|
|
17
|
-
*
|
|
18
|
-
* // Trigger fireworks
|
|
19
|
-
* trigger();
|
|
20
|
-
*
|
|
21
|
-
* // Render particles
|
|
22
|
-
* {particles.map((particle, index) => (
|
|
23
|
-
* <Particle key={index} {...particle} />
|
|
24
|
-
* ))}
|
|
25
|
-
*/
|
|
26
|
-
export const useFireworks = (config: FireworksConfig) => {
|
|
27
|
-
const [particles, setParticles] = useState<ParticleConfig[]>([]);
|
|
28
|
-
const [isActive, setIsActive] = useState(false);
|
|
29
|
-
const animationFrameRef = useRef<number | null>(null);
|
|
30
|
-
const particlesRef = useRef<ParticleConfig[]>([]);
|
|
31
|
-
|
|
32
|
-
const {
|
|
33
|
-
particleCount = FIREWORKS_CONSTANTS.DEFAULT_PARTICLE_COUNT,
|
|
34
|
-
colors,
|
|
35
|
-
duration = FIREWORKS_CONSTANTS.DEFAULT_DURATION,
|
|
36
|
-
particleSize = FIREWORKS_CONSTANTS.DEFAULT_PARTICLE_SIZE,
|
|
37
|
-
spread = FIREWORKS_CONSTANTS.DEFAULT_SPREAD,
|
|
38
|
-
} = config;
|
|
39
|
-
|
|
40
|
-
if (!colors || colors.length === 0) {
|
|
41
|
-
// Return no-op when colors not provided
|
|
42
|
-
return { particles: [], trigger: () => { }, isActive: false };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const createParticle = useCallback((
|
|
46
|
-
x: number,
|
|
47
|
-
y: number,
|
|
48
|
-
color: string
|
|
49
|
-
): ParticleConfig => {
|
|
50
|
-
const angle = Math.random() * Math.PI * 2;
|
|
51
|
-
const velocity = Math.random() * spread + 50;
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
x,
|
|
55
|
-
y,
|
|
56
|
-
color,
|
|
57
|
-
size: particleSize + Math.random() * 2,
|
|
58
|
-
velocityX: Math.cos(angle) * velocity,
|
|
59
|
-
velocityY: Math.sin(angle) * velocity,
|
|
60
|
-
life: 1.0,
|
|
61
|
-
decay: FIREWORKS_CONSTANTS.DECAY_RATE + Math.random() * 0.01,
|
|
62
|
-
};
|
|
63
|
-
}, [particleSize, spread]);
|
|
64
|
-
|
|
65
|
-
const isActiveRef = useRef(false);
|
|
66
|
-
|
|
67
|
-
const updateParticles = useCallback(() => {
|
|
68
|
-
const currentParticles = [...particlesRef.current];
|
|
69
|
-
const updated: ParticleConfig[] = [];
|
|
70
|
-
|
|
71
|
-
for (const particle of currentParticles) {
|
|
72
|
-
const newX = particle.x + particle.velocityX * 0.1;
|
|
73
|
-
const newY = particle.y + particle.velocityY * 0.1 + FIREWORKS_CONSTANTS.GRAVITY;
|
|
74
|
-
const newVelocityY = particle.velocityY + FIREWORKS_CONSTANTS.GRAVITY;
|
|
75
|
-
const newLife = particle.life - particle.decay;
|
|
76
|
-
|
|
77
|
-
if (newLife > 0) {
|
|
78
|
-
updated.push({
|
|
79
|
-
...particle,
|
|
80
|
-
x: newX,
|
|
81
|
-
y: newY,
|
|
82
|
-
velocityY: newVelocityY,
|
|
83
|
-
life: newLife,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
particlesRef.current = updated;
|
|
89
|
-
setParticles(updated);
|
|
90
|
-
|
|
91
|
-
if (updated.length > 0 && isActiveRef.current) {
|
|
92
|
-
animationFrameRef.current = requestAnimationFrame(updateParticles);
|
|
93
|
-
} else {
|
|
94
|
-
setIsActive(false);
|
|
95
|
-
isActiveRef.current = false;
|
|
96
|
-
}
|
|
97
|
-
}, [setIsActive]); // Removed isActive dependency
|
|
98
|
-
|
|
99
|
-
const trigger = useCallback((x?: number, y?: number) => {
|
|
100
|
-
const centerX = x ?? 0;
|
|
101
|
-
const centerY = y ?? 0;
|
|
102
|
-
|
|
103
|
-
const newParticles: ParticleConfig[] = [];
|
|
104
|
-
for (let i = 0; i < particleCount; i++) {
|
|
105
|
-
const colorIndex = Math.floor(Math.random() * colors.length);
|
|
106
|
-
const color = colors[colorIndex] ?? colors[0] ?? '#FFFFFF';
|
|
107
|
-
newParticles.push(createParticle(centerX, centerY, color));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Create new array reference to avoid worklet issues
|
|
111
|
-
const particlesArray = [...newParticles];
|
|
112
|
-
particlesRef.current = particlesArray;
|
|
113
|
-
setParticles(particlesArray);
|
|
114
|
-
setIsActive(true);
|
|
115
|
-
isActiveRef.current = true;
|
|
116
|
-
|
|
117
|
-
if (animationFrameRef.current) {
|
|
118
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
119
|
-
}
|
|
120
|
-
animationFrameRef.current = requestAnimationFrame(updateParticles);
|
|
121
|
-
|
|
122
|
-
// Auto-stop after duration
|
|
123
|
-
setTimeout(() => {
|
|
124
|
-
setIsActive(false);
|
|
125
|
-
if (animationFrameRef.current) {
|
|
126
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
127
|
-
}
|
|
128
|
-
}, duration);
|
|
129
|
-
}, [particleCount, colors, duration, createParticle, updateParticles]);
|
|
130
|
-
|
|
131
|
-
useEffect(() => {
|
|
132
|
-
return () => {
|
|
133
|
-
if (animationFrameRef.current) {
|
|
134
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
}, []);
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
particles,
|
|
141
|
-
trigger,
|
|
142
|
-
isActive,
|
|
143
|
-
};
|
|
144
|
-
};
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useGesture Hook
|
|
3
|
-
*
|
|
4
|
-
* Orchestrator hook that combines gesture creators and state.
|
|
5
|
-
* Single Responsibility: Compose and expose gesture functionality.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { GestureDetector } from 'react-native-gesture-handler';
|
|
9
|
-
import { useGestureState } from './useGestureState';
|
|
10
|
-
import { useGestureCreators } from './useGestureCreators';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Hook for gesture handling
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* const { createPanGesture, animatedStyle, GestureDetector } = useGesture();
|
|
18
|
-
*
|
|
19
|
-
* const panGesture = createPanGesture({
|
|
20
|
-
* onEnd: (x, y) => console.log('Dragged to:', x, y),
|
|
21
|
-
* });
|
|
22
|
-
*
|
|
23
|
-
* return (
|
|
24
|
-
* <GestureDetector gesture={panGesture}>
|
|
25
|
-
* <Animated.View style={animatedStyle}>...</Animated.View>
|
|
26
|
-
* </GestureDetector>
|
|
27
|
-
* );
|
|
28
|
-
*/
|
|
29
|
-
export const useGesture = () => {
|
|
30
|
-
const state = useGestureState();
|
|
31
|
-
const creators = useGestureCreators(state);
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
// Gesture creators
|
|
35
|
-
createTapGesture: creators.createTapGesture,
|
|
36
|
-
createPanGesture: creators.createPanGesture,
|
|
37
|
-
createPinchGesture: creators.createPinchGesture,
|
|
38
|
-
createLongPressGesture: creators.createLongPressGesture,
|
|
39
|
-
// Shared values (for custom gestures)
|
|
40
|
-
translateX: state.translateX,
|
|
41
|
-
translateY: state.translateY,
|
|
42
|
-
scale: state.scale,
|
|
43
|
-
// Utilities
|
|
44
|
-
reset: state.reset,
|
|
45
|
-
// Animated style
|
|
46
|
-
animatedStyle: state.animatedStyle,
|
|
47
|
-
// Re-export GestureDetector for convenience
|
|
48
|
-
GestureDetector: GestureDetector as typeof GestureDetector,
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Re-export types for convenience
|
|
53
|
-
export type {
|
|
54
|
-
TapGestureOptions,
|
|
55
|
-
PanGestureOptions,
|
|
56
|
-
PinchGestureOptions,
|
|
57
|
-
} from './useGestureCreators';
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useGestureCreators Hook
|
|
3
|
-
*
|
|
4
|
-
* Hook for creating gesture handlers.
|
|
5
|
-
* Single Responsibility: Create gesture handlers only.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { useCallback } from 'react';
|
|
9
|
-
import {
|
|
10
|
-
runOnJS,
|
|
11
|
-
} from 'react-native-reanimated';
|
|
12
|
-
import {
|
|
13
|
-
Gesture,
|
|
14
|
-
} from 'react-native-gesture-handler';
|
|
15
|
-
import type {
|
|
16
|
-
SharedValue,
|
|
17
|
-
} from 'react-native-reanimated';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Tap gesture options
|
|
21
|
-
*/
|
|
22
|
-
export interface TapGestureOptions {
|
|
23
|
-
numberOfTaps?: number;
|
|
24
|
-
maxDuration?: number;
|
|
25
|
-
onTap?: () => void;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Pan gesture options
|
|
30
|
-
*/
|
|
31
|
-
export interface PanGestureOptions {
|
|
32
|
-
onStart?: () => void;
|
|
33
|
-
onUpdate?: (x: number, y: number) => void;
|
|
34
|
-
onEnd?: (x: number, y: number) => void;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Pinch gesture options
|
|
39
|
-
*/
|
|
40
|
-
export interface PinchGestureOptions {
|
|
41
|
-
onStart?: () => void;
|
|
42
|
-
onUpdate?: (scale: number) => void;
|
|
43
|
-
onEnd?: (scale: number) => void;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Long press gesture options
|
|
48
|
-
*/
|
|
49
|
-
export interface LongPressGestureOptions {
|
|
50
|
-
minDuration?: number;
|
|
51
|
-
onLongPress?: () => void;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Gesture state interface
|
|
56
|
-
*/
|
|
57
|
-
export interface GestureState {
|
|
58
|
-
translateX: SharedValue<number>;
|
|
59
|
-
translateY: SharedValue<number>;
|
|
60
|
-
scale: SharedValue<number>;
|
|
61
|
-
savedTranslateX: SharedValue<number>;
|
|
62
|
-
savedTranslateY: SharedValue<number>;
|
|
63
|
-
savedScale: SharedValue<number>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Hook for creating gesture handlers
|
|
68
|
-
*/
|
|
69
|
-
export const useGestureCreators = (state: GestureState) => {
|
|
70
|
-
const { translateX, translateY, scale, savedTranslateX, savedTranslateY, savedScale } = state;
|
|
71
|
-
|
|
72
|
-
const createTapGesture = useCallback(
|
|
73
|
-
(options: TapGestureOptions = {}) => {
|
|
74
|
-
const { numberOfTaps = 1, maxDuration = 500, onTap } = options;
|
|
75
|
-
|
|
76
|
-
return Gesture.Tap()
|
|
77
|
-
.numberOfTaps(numberOfTaps)
|
|
78
|
-
.maxDuration(maxDuration)
|
|
79
|
-
.onStart(() => {
|
|
80
|
-
if (onTap) {
|
|
81
|
-
runOnJS(onTap)();
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
},
|
|
85
|
-
[]
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
const createPanGesture = useCallback(
|
|
89
|
-
(options: PanGestureOptions = {}) => {
|
|
90
|
-
const { onStart, onUpdate, onEnd } = options;
|
|
91
|
-
|
|
92
|
-
return Gesture.Pan()
|
|
93
|
-
.onStart(() => {
|
|
94
|
-
savedTranslateX.value = translateX.value;
|
|
95
|
-
savedTranslateY.value = translateY.value;
|
|
96
|
-
if (onStart) {
|
|
97
|
-
runOnJS(onStart)();
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
.onUpdate((event: any) => {
|
|
101
|
-
translateX.value = savedTranslateX.value + event.translationX;
|
|
102
|
-
translateY.value = savedTranslateY.value + event.translationY;
|
|
103
|
-
if (onUpdate) {
|
|
104
|
-
runOnJS(onUpdate)(translateX.value, translateY.value);
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
.onEnd(() => {
|
|
108
|
-
if (onEnd) {
|
|
109
|
-
runOnJS(onEnd)(translateX.value, translateY.value);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
},
|
|
113
|
-
[translateX, translateY, savedTranslateX, savedTranslateY]
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const createPinchGesture = useCallback(
|
|
117
|
-
(options: PinchGestureOptions = {}) => {
|
|
118
|
-
const { onStart, onUpdate, onEnd } = options;
|
|
119
|
-
|
|
120
|
-
return Gesture.Pinch()
|
|
121
|
-
.onStart(() => {
|
|
122
|
-
savedScale.value = scale.value;
|
|
123
|
-
if (onStart) {
|
|
124
|
-
runOnJS(onStart)();
|
|
125
|
-
}
|
|
126
|
-
})
|
|
127
|
-
.onUpdate((event: any) => {
|
|
128
|
-
scale.value = savedScale.value * event.scale;
|
|
129
|
-
if (onUpdate) {
|
|
130
|
-
runOnJS(onUpdate)(scale.value);
|
|
131
|
-
}
|
|
132
|
-
})
|
|
133
|
-
.onEnd(() => {
|
|
134
|
-
if (onEnd) {
|
|
135
|
-
runOnJS(onEnd)(scale.value);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
},
|
|
139
|
-
[scale, savedScale]
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
const createLongPressGesture = useCallback(
|
|
143
|
-
(options: LongPressGestureOptions = {}) => {
|
|
144
|
-
const { minDuration = 500, onLongPress } = options;
|
|
145
|
-
|
|
146
|
-
return Gesture.LongPress()
|
|
147
|
-
.minDuration(minDuration)
|
|
148
|
-
.onStart(() => {
|
|
149
|
-
if (onLongPress) {
|
|
150
|
-
runOnJS(onLongPress)();
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
},
|
|
154
|
-
[]
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
createTapGesture,
|
|
159
|
-
createPanGesture,
|
|
160
|
-
createPinchGesture,
|
|
161
|
-
createLongPressGesture,
|
|
162
|
-
};
|
|
163
|
-
};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useGestureState Hook
|
|
3
|
-
*
|
|
4
|
-
* Hook for managing gesture state (shared values, reset).
|
|
5
|
-
* Single Responsibility: Manage gesture state only.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { useCallback } from 'react';
|
|
9
|
-
import {
|
|
10
|
-
useSharedValue,
|
|
11
|
-
useAnimatedStyle,
|
|
12
|
-
withSpring,
|
|
13
|
-
} from 'react-native-reanimated';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Hook for managing gesture state
|
|
17
|
-
*/
|
|
18
|
-
export const useGestureState = () => {
|
|
19
|
-
const translateX = useSharedValue(0);
|
|
20
|
-
const translateY = useSharedValue(0);
|
|
21
|
-
const scale = useSharedValue(1);
|
|
22
|
-
const savedTranslateX = useSharedValue(0);
|
|
23
|
-
const savedTranslateY = useSharedValue(0);
|
|
24
|
-
const savedScale = useSharedValue(1);
|
|
25
|
-
|
|
26
|
-
const reset = useCallback(() => {
|
|
27
|
-
translateX.value = withSpring(0);
|
|
28
|
-
translateY.value = withSpring(0);
|
|
29
|
-
scale.value = withSpring(1);
|
|
30
|
-
savedTranslateX.value = 0;
|
|
31
|
-
savedTranslateY.value = 0;
|
|
32
|
-
savedScale.value = 1;
|
|
33
|
-
}, [translateX, translateY, scale, savedTranslateX, savedTranslateY, savedScale]);
|
|
34
|
-
|
|
35
|
-
const animatedStyle = useAnimatedStyle(() => ({
|
|
36
|
-
transform: [
|
|
37
|
-
{ translateX: translateX.value },
|
|
38
|
-
{ translateY: translateY.value },
|
|
39
|
-
{ scale: scale.value },
|
|
40
|
-
] as any,
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
|
-
return {
|
|
44
|
-
translateX,
|
|
45
|
-
translateY,
|
|
46
|
-
scale,
|
|
47
|
-
savedTranslateX,
|
|
48
|
-
savedTranslateY,
|
|
49
|
-
savedScale,
|
|
50
|
-
reset,
|
|
51
|
-
animatedStyle,
|
|
52
|
-
};
|
|
53
|
-
};
|