UNPKG

@td-design/react-native

Version:

react-native UI组件库

135 lines (131 loc) 3.88 kB
import { useEffect } from 'react'; import { BackHandler, Dimensions } from 'react-native'; import { runOnJS, useAnimatedStyle, useSharedValue, withSpring, withTiming } from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useTheme } from '@shopify/restyle'; import { useMemoizedFn, usePrevious, useSafeState } from '@td-design/rn-hooks'; const screen = Dimensions.get('screen'); const getPosition = visible => { return visible ? 0 : screen.height; }; const getScale = visible => { 'worklet'; return visible ? 1 : 1.05; }; const getOpacity = visible => { 'worklet'; return visible ? 1 : 0; }; export default function useModal(_ref) { let { animationType, animationDuration, visible, maskClosable, position, onClose, onAnimationEnd, onRequestClose } = _ref; const theme = useTheme(); const insets = useSafeAreaInsets(); const prevVisible = usePrevious(visible); const translateY = useSharedValue(0); const scale = useSharedValue(1); const opacity = useSharedValue(1); // 通过modalVisible来控制modal的显示和隐藏,之所以要用modalVisible,是想要让modal的显隐有动画效果 const [modalVisible, setModalVisible] = useSafeState(visible); useEffect(() => { if (visible) { setModalVisible(true); } }, [visible]); const onBackAndroid = useMemoizedFn(() => { if (typeof onRequestClose === 'function') { return onRequestClose(); } onClose === null || onClose === void 0 ? void 0 : onClose(); return visible ? true : false; // 返回true表示拦截了返回键 }); useEffect(() => { const backHandler = BackHandler.addEventListener('hardwareBackPress', onBackAndroid); return () => backHandler.remove(); }, [onBackAndroid]); const animateCallback = useMemoizedFn(visible => { setModalVisible(visible); onAnimationEnd === null || onAnimationEnd === void 0 ? void 0 : onAnimationEnd(visible); }); useEffect(() => { if (prevVisible !== visible) { if (animationType === 'slide') { translateY.value = withTiming(getPosition(visible), { duration: animationDuration }, () => { runOnJS(animateCallback)(visible); }); } else if (animationType === 'fade') { opacity.value = withTiming(getOpacity(visible), { duration: animationDuration }); scale.value = withSpring(getScale(visible), {}, () => { runOnJS(animateCallback)(visible); }); } } }, [visible, animationType, position, animationDuration]); const handleMaskClose = () => { if (maskClosable) { onClose === null || onClose === void 0 ? void 0 : onClose(); } }; const slideStyle = useAnimatedStyle(() => { return { transform: [{ translateY: translateY.value }] }; }); const fadeStyle = useAnimatedStyle(() => { return { transform: [{ scale: scale.value }], opacity: opacity.value }; }); const animationStyleMap = { slide: slideStyle, fade: fadeStyle }; const defaultStyle = { flexDirection: position === 'bottom' ? 'column-reverse' : 'column' }; const wrapStyle = { backgroundColor: theme.colors.white, borderRadius: theme.borderRadii.x3 }; switch (position) { case 'top': wrapStyle.paddingTop = insets.top; break; case 'bottom': wrapStyle.paddingBottom = insets.bottom; break; case 'center': defaultStyle.justifyContent = 'center'; break; case 'fullscreen': wrapStyle.flex = 1; wrapStyle.paddingTop = insets.top; wrapStyle.paddingBottom = insets.bottom; break; } return { modalVisible, wrapStyle, defaultStyle, handleMaskClose, animationStyleMap }; } //# sourceMappingURL=useModal.js.map