Поставьте зависимости:
npm install expo-blur expo-haptics react-native-reanimatedpnpm add expo-blur expo-haptics react-native-reanimatedyarn add expo-blur expo-haptics react-native-reanimatedbun add expo-blur expo-haptics react-native-reanimatedСкопируйте эти файлы в src/shared/components/atoms/pressable/:
Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.
import { useEffect, useMemo, useRef } from "react";
import { View, StyleSheet, Text } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { StatusBar } from "expo-status-bar";
import { useFonts } from "expo-font";
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring,
} from "react-native-reanimated";
import { Pressable } from "@/shared/components/atoms/pressable";
import { Showcase, useAutoplay, useCustomize } from "~/showcase";
const PRESS_SPRING = { stiffness: 550, mass: 0.5, damping: 50 };
const BUTTON_HEX = "#ffffff";
const LABEL_HEX = "#000000";
const CUSTOMIZE = [
{ key: "label", label: "Текст кнопки", type: "text", default: "Get Started", maxLength: 24 },
{ key: "background", label: "Цвет кнопки", type: "color", default: BUTTON_HEX },
{ key: "color", label: "Цвет текста", type: "color", default: LABEL_HEX },
{ key: "scale", label: "Сжатие", type: "slider", min: 0.8, max: 1, step: 0.01, default: 0.97 },
{ key: "rotate", label: "Поворот", type: "slider", min: -15, max: 15, step: 0.5, unit: "°", default: -5 },
{ key: "stiffness", label: "Жёсткость", type: "slider", min: 100, max: 1000, step: 10, default: 550 },
{ key: "damping", label: "Затухание", type: "slider", min: 5, max: 100, step: 1, default: 50 },
{ key: "hold", label: "Удержание", type: "slider", min: 200, max: 2000, step: 20, unit: "ms", default: 580 },
] as const;
export default function App() {
const [fontLoaded] = useFonts({
SfProRounded: require("@/assets/fonts/sf-pro-rounded.ttf"),
});
const custom = useCustomize(CUSTOMIZE);
const demoPress = useSharedValue(0);
const pressDepth = useSharedValue(1 - custom.scale);
const pressRotate = useSharedValue(custom.rotate);
useEffect(() => {
pressDepth.value = 1 - custom.scale;
pressRotate.value = custom.rotate;
}, [custom.scale, custom.rotate, pressDepth, pressRotate]);
const spring = useMemo(
() =>
custom.stiffness === PRESS_SPRING.stiffness &&
custom.damping === PRESS_SPRING.damping
? PRESS_SPRING
: { ...PRESS_SPRING, stiffness: custom.stiffness, damping: custom.damping },
[custom.stiffness, custom.damping],
);
const live = useRef({ spring, hold: custom.hold });
live.current = { spring, hold: custom.hold };
const demoPressStyle = useAnimatedStyle(() => ({
transform: [
{ scale: 1 - pressDepth.value * demoPress.value },
{ rotate: `${pressRotate.value * demoPress.value}deg` },
],
}));
useAutoplay(async ({ wait }) => {
try {
await wait(800);
demoPress.value = withSpring(1, live.current.spring);
await wait(live.current.hold);
demoPress.value = withSpring(0, live.current.spring);
await wait(300);
} catch (error) {
demoPress.value = withSpring(0, live.current.spring);
throw error;
}
});
return (
<Showcase>
<GestureHandlerRootView style={styles.container}>
<StatusBar style="light" />
<Animated.View style={demoPressStyle}>
<Pressable
pressAnimation={{
scale: custom.scale,
useSpring: true,
stiffness: custom.stiffness,
mass: 0.5,
damping: custom.damping,
rotate: custom.rotate,
}}
feedback={{ haptic: true, hapticType: "medium" }}
>
<View
style={[
styles.btn,
custom.background !== BUTTON_HEX && { backgroundColor: custom.background },
!fontLoaded && styles.pending,
]}
>
<Text
style={[
styles.btnText,
custom.color !== LABEL_HEX && { color: custom.color },
fontLoaded && { fontFamily: "SfProRounded" },
]}
>
{custom.label}
</Text>
</View>
</Pressable>
</Animated.View>
</GestureHandlerRootView>
</Showcase>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#0a0a0a",
justifyContent: "center",
alignItems: "center",
},
btn: {
flexDirection: "row",
alignItems: "center",
gap: 10,
backgroundColor: "#fff",
paddingVertical: 16,
paddingHorizontal: 32,
borderRadius: 99,
},
pending: {
opacity: 0,
},
btnText: {
fontSize: 17,
fontWeight: "600",
color: "#000",
},
});childrenТип ReactNode
onPress?Тип (event: GestureResponderEvent) => void
onLongPress?Тип (event: GestureResponderEvent) => void
onPressIn?Тип (event: GestureResponderEvent) => void
onPressOut?Тип (event: GestureResponderEvent) => void
longPressDuration?Тип number
disabled?Тип boolean
style?Тип ViewStyle | ViewStyle[]
pressAnimation?Тип AnimationConfig
longPressAnimation?Тип AnimationConfig
customAnimation?Тип CustomAnimation
feedback?Тип FeedbackConfig
blur?Тип BlurConfig
disableAnimations?Тип boolean
skipGlobalCallback?Тип boolean
testID?Тип string
accessibilityLabel?Тип string
accessibilityHint?Тип string
accessibilityRole?Тип "button" | "link" | "none"