react-native-modern-elements
Version:
A modern, customizable UI component library for React Native
158 lines (157 loc) • 6.22 kB
JavaScript
import React, { memo, useEffect } from "react";
import { BackHandler, Modal, StatusBar, StyleSheet, TouchableWithoutFeedback, } from "react-native";
import Animated, { useAnimatedStyle, useSharedValue, withSpring, } from "react-native-reanimated";
const Modals = ({ visible, children, animation, onClose, modalContainer, }) => {
const [showModal, setShowModal] = React.useState(visible);
const translateX = useSharedValue(0);
const translateY = useSharedValue(500);
const scaleValue = useSharedValue(0);
// open and close animation
useEffect(() => {
if (visible) {
setShowModal(true);
// Opening animations
if (animation === "LeftToCenterCloseToRight") {
// Start position (off-screen left)
translateX.value = -500;
// Animate to center (0)
translateX.value = withSpring(0, {
damping: 11.9, // smooth
stiffness: 80, // smooth
mass: 0.9,
});
}
else if (animation === "center") {
scaleValue.value = 0;
scaleValue.value = withSpring(1, {
damping: 8,
stiffness: 80,
mass: 0.8,
});
}
else if (animation === "BottomToCenterCloseToBottom") {
translateY.value = 500;
translateY.value = withSpring(0, {
damping: 10,
stiffness: 70,
mass: 0.8,
});
}
else if (animation === "RightToCenterCloseToLeft") {
translateX.value = 500; // start from right
translateX.value = withSpring(0, {
damping: 11.9,
stiffness: 80,
mass: 0.9,
});
}
else if (animation === "LeftToCenterCloseToLeft") {
translateX.value = -500;
translateX.value = withSpring(0, {
damping: 11.9,
stiffness: 80,
mass: 0.9,
});
}
else if (animation === "RightToCenterCloseToRight") {
translateX.value = 500;
translateX.value = withSpring(0, {
damping: 11.9,
stiffness: 80,
mass: 0.9,
});
}
const backHandler = BackHandler.addEventListener("hardwareBackPress", () => {
onClose();
return true;
});
return () => backHandler.remove();
}
else {
// Closing animations
if (animation === "LeftToCenterCloseToRight") {
translateX.value = withSpring(500, {
damping: 8, // smooth
stiffness: 80, // smooth
mass: 0.8,
});
}
else if (animation === "center") {
scaleValue.value = withSpring(0, {
damping: 14,
stiffness: 90,
mass: 1,
});
}
else if (animation === "BottomToCenterCloseToBottom") {
translateY.value = withSpring(700, {
damping: 10,
stiffness: 80,
mass: 0.8,
});
}
else if (animation === "RightToCenterCloseToLeft") {
translateX.value = withSpring(-500, {
damping: 11.9,
stiffness: 80,
mass: 0.9,
}); // close to left
}
else if (animation === "LeftToCenterCloseToLeft") {
translateX.value = withSpring(-500, {
damping: 11.9,
stiffness: 80,
mass: 0.9,
});
}
else if (animation === "RightToCenterCloseToRight") {
translateX.value = withSpring(500, {
damping: 11.9,
stiffness: 80,
mass: 0.9,
});
}
setTimeout(() => setShowModal(false), 350);
}
}, [visible, animation, onClose, scaleValue, translateX, translateY]);
const modalStyle = useAnimatedStyle(() => {
let transformStyles = [];
if (animation === "center") {
transformStyles = [{ scale: scaleValue.value }];
}
else if (animation === "LeftToCenterCloseToRight" ||
animation === "RightToCenterCloseToLeft" ||
animation === "LeftToCenterCloseToLeft" ||
animation === "RightToCenterCloseToRight") {
transformStyles = [{ translateX: translateX.value }];
}
else if (animation === "BottomToCenterCloseToBottom") {
transformStyles = [{ translateY: translateY.value }];
}
return { transform: transformStyles };
});
return (React.createElement(Modal, { transparent: true, visible: showModal, onRequestClose: onClose, statusBarTranslucent: true },
showModal && (React.createElement(StatusBar, { backgroundColor: "#797777", barStyle: "light-content", animated: true })),
React.createElement(TouchableWithoutFeedback, { onPress: onClose },
React.createElement(Animated.View, { style: styles.modalBackground },
React.createElement(TouchableWithoutFeedback, null,
React.createElement(Animated.View, { style: [styles.modalContainer, modalStyle, modalContainer] }, children))))));
};
const styles = StyleSheet.create({
modalBackground: {
flex: 1,
backgroundColor: "rgba(0, 0, 0, 0.5)",
justifyContent: "center",
alignItems: "center",
overflow: "hidden",
},
modalContainer: {
width: "80%",
backgroundColor: "white",
paddingHorizontal: 20,
paddingVertical: 30,
borderRadius: 20,
elevation: 20,
},
});
export default memo(Modals);