1// Prevent pulling in all of expo-modules-core on web 2import { EventEmitter } from 'expo-modules-core/build/EventEmitter'; 3import React, { useEffect, useState, useRef, useMemo } from 'react'; 4import { Animated, StyleSheet, Text, Platform, View } from 'react-native'; 5import DevLoadingViewNativeModule from './DevLoadingViewNativeModule'; 6import { getInitialSafeArea } from './getInitialSafeArea'; 7export default function DevLoadingView() { 8 const [message, setMessage] = useState('Refreshing...'); 9 const [isDevLoading, setIsDevLoading] = useState(false); 10 const [isAnimating, setIsAnimating] = useState(false); 11 const translateY = useRef(new Animated.Value(0)).current; 12 const emitter = useMemo(() => { 13 try { 14 return new EventEmitter(DevLoadingViewNativeModule); 15 } 16 catch (error) { 17 throw new Error('Failed to instantiate native emitter in `DevLoadingView` because the native module `DevLoadingView` is undefined: ' + 18 error.message); 19 } 20 }, []); 21 useEffect(() => { 22 if (!emitter) 23 return; 24 function handleShowMessage(event) { 25 setMessage(event.message); 26 // TODO: if we show the refreshing banner and don't get a hide message 27 // for 3 seconds, warn the user that it's taking a while and suggest 28 // they reload 29 translateY.setValue(0); 30 setIsDevLoading(true); 31 } 32 function handleHide() { 33 // TODO: if we showed the 'refreshing' banner less than 250ms ago, delay 34 // switching to the 'finished' banner 35 setIsAnimating(true); 36 setIsDevLoading(false); 37 Animated.timing(translateY, { 38 toValue: 150, 39 delay: 1000, 40 duration: 350, 41 useNativeDriver: Platform.OS !== 'web', 42 }).start(({ finished }) => { 43 if (finished) { 44 setIsAnimating(false); 45 translateY.setValue(0); 46 } 47 }); 48 } 49 const showMessageSubscription = emitter.addListener('devLoadingView:showMessage', handleShowMessage); 50 const hideSubscription = emitter.addListener('devLoadingView:hide', handleHide); 51 return function cleanup() { 52 showMessageSubscription.remove(); 53 hideSubscription.remove(); 54 }; 55 }, [translateY, emitter]); 56 if (!isDevLoading && !isAnimating) { 57 return null; 58 } 59 return (React.createElement(Animated.View, { style: [styles.animatedContainer, { transform: [{ translateY }] }] }, 60 React.createElement(View, { style: styles.banner }, 61 React.createElement(View, { style: styles.contentContainer }, 62 React.createElement(View, { style: { flexDirection: 'row' } }, 63 React.createElement(Text, { style: styles.text }, message)), 64 React.createElement(View, { style: { flex: 1 } }, 65 React.createElement(Text, { style: styles.subtitle }, isDevLoading ? 'Using Fast Refresh' : "Don't see your changes? Reload the app")))))); 66} 67const styles = StyleSheet.create({ 68 animatedContainer: { 69 // @ts-expect-error: fixed is not a valid value for position in Yoga but it is on web. 70 position: Platform.select({ 71 web: 'fixed', 72 default: 'absolute', 73 }), 74 pointerEvents: 'none', 75 bottom: 0, 76 left: 0, 77 right: 0, 78 zIndex: 42, // arbitrary 79 }, 80 banner: { 81 flex: 1, 82 overflow: 'visible', 83 backgroundColor: 'rgba(0,0,0,0.75)', 84 paddingBottom: getInitialSafeArea().bottom, 85 }, 86 contentContainer: { 87 flex: 1, 88 paddingTop: 10, 89 paddingBottom: 5, 90 alignItems: 'center', 91 justifyContent: 'center', 92 textAlign: 'center', 93 }, 94 text: { 95 color: '#fff', 96 fontSize: 15, 97 }, 98 subtitle: { 99 color: 'rgba(255,255,255,0.8)', 100 }, 101}); 102//# sourceMappingURL=DevLoadingView.js.map