Skip to content

Commit 4024544

Browse files
committed
feat(utils): ✨ create useScaleAnimation hook for Tappable components
1 parent f538bc7 commit 4024544

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ export * from "./isUndefined";
1111
export * from "./react";
1212
export * from "./styleAdapter";
1313
export * from "./types";
14+
export * from "./useScaleAnimation";

src/utils/useScaleAnimation.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { useCallback, useMemo } from "react";
2+
import {
3+
useAnimatedStyle,
4+
useSharedValue,
5+
withSpring,
6+
WithSpringConfig,
7+
withTiming,
8+
WithTimingConfig,
9+
} from "react-native-reanimated";
10+
11+
type AnimationValue = {
12+
/**
13+
* The scale value to which the component should resize onPressIn
14+
* @default 0.95
15+
*/
16+
value: number;
17+
};
18+
19+
type SpringAnimation = AnimationValue & {
20+
/**
21+
* The animation type
22+
* @default "spring"
23+
*/
24+
type: "spring";
25+
config: WithSpringConfig;
26+
};
27+
28+
type TimingAnimation = AnimationValue & {
29+
/**
30+
* The animation type
31+
* @default "spring"
32+
*/
33+
type: "timing";
34+
config: WithTimingConfig;
35+
};
36+
37+
type AnimationTypes = SpringAnimation | TimingAnimation;
38+
39+
const DefaultSpringConfig: WithSpringConfig = {
40+
mass: 1,
41+
damping: 17,
42+
stiffness: 230,
43+
overshootClamping: false,
44+
restSpeedThreshold: 0.001,
45+
restDisplacementThreshold: 0.001,
46+
};
47+
48+
const DefaultAnimationType: AnimationTypes = {
49+
type: "spring",
50+
config: DefaultSpringConfig,
51+
value: 0.96,
52+
};
53+
54+
export const useScaleAnimation = (
55+
scaleAnimationConfig: AnimationTypes = DefaultAnimationType,
56+
) => {
57+
const scale = useSharedValue(1);
58+
const { type, config, value } = scaleAnimationConfig;
59+
60+
const getAnimation = useCallback((animationValue: number) => {
61+
if (type === "spring") {
62+
return withSpring(animationValue, config);
63+
} else {
64+
return withTiming(animationValue, config);
65+
}
66+
// eslint-disable-next-line react-hooks/exhaustive-deps
67+
}, []);
68+
69+
const onPressIn = useCallback(() => {
70+
scale.value = getAnimation(value);
71+
// eslint-disable-next-line react-hooks/exhaustive-deps
72+
}, []);
73+
74+
const onPressOut = useCallback(() => {
75+
scale.value = getAnimation(1);
76+
// eslint-disable-next-line react-hooks/exhaustive-deps
77+
}, []);
78+
79+
const animatedStyle = useAnimatedStyle(() => ({
80+
transform: [{ scale: scale.value }],
81+
}));
82+
83+
const scaleAnimationHandler = useMemo(() => {
84+
return {
85+
handlers: { onPressIn, onPressOut },
86+
animatedStyle,
87+
};
88+
}, [animatedStyle, onPressIn, onPressOut]);
89+
90+
return scaleAnimationHandler;
91+
};

0 commit comments

Comments
 (0)