expo-router
Version:
Expo Router is a file-based router for React Native and web applications.
183 lines (179 loc) • 6.86 kB
JavaScript
'use client';
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorBoundary = ErrorBoundary;
const bottom_tabs_1 = require("@react-navigation/bottom-tabs");
const react_1 = require("react");
const react_native_1 = require("react-native");
const react_native_safe_area_context_1 = require("react-native-safe-area-context");
const Pressable_1 = require("./Pressable");
const Link_1 = require("../link/Link");
const errors_1 = require("../rsc/router/errors");
function StandardErrorView({ error }) {
return (<react_native_1.View style={{
marginBottom: 12,
gap: 4,
flexWrap: process.env.EXPO_OS === 'web' ? 'wrap' : 'nowrap',
}}>
<react_native_1.Text role="heading" aria-level={1} style={styles.title}>
Something went wrong
</react_native_1.Text>
<react_native_1.Text testID="router_error_message" role="heading" aria-level={2} style={styles.errorMessage}>
Error: {error.message}
</react_native_1.Text>
</react_native_1.View>);
}
function ErrorBoundary({ error, retry }) {
const inTabBar = (0, react_1.use)(bottom_tabs_1.BottomTabBarHeightContext);
const Wrapper = inTabBar ? react_native_1.View : react_native_safe_area_context_1.SafeAreaView;
const isServerError = error instanceof errors_1.ReactServerError;
return (<react_native_1.View style={styles.container}>
<Wrapper style={{ flex: 1, gap: 8, maxWidth: 720, marginHorizontal: 'auto' }}>
{isServerError ? (<ReactServerErrorView error={error}/>) : (<StandardErrorView error={error}/>)}
<react_native_1.View style={{ flex: 1 }}/>
{process.env.NODE_ENV === 'development' && (<Link_1.Link testID="router_error_sitemap" href="/_sitemap" style={styles.link}>
Sitemap
</Link_1.Link>)}
<Pressable_1.Pressable testID="router_error_retry" onPress={retry}>
{({ hovered, pressed }) => (<react_native_1.View style={[styles.buttonInner, (hovered || pressed) && { backgroundColor: 'white' }]}>
<react_native_1.Text style={[
styles.buttonText,
{
color: hovered || pressed ? 'black' : 'white',
},
]}>
Retry
</react_native_1.Text>
</react_native_1.View>)}
</Pressable_1.Pressable>
</Wrapper>
</react_native_1.View>);
}
const COMMON_ERROR_STATUS = {
404: 'NOT_FOUND',
500: 'INTERNAL_SERVER_ERROR',
503: 'SERVICE_UNAVAILABLE',
504: 'GATEWAY_TIMEOUT',
};
// TODO: This should probably be replaced by a DOM component that loads server errors in the future.
function ReactServerErrorView({ error }) {
let title = String(error.statusCode);
title += ': ' + (COMMON_ERROR_STATUS[error.statusCode] ?? 'Server Error');
const errorId = error.headers.get('cf-ray');
const date = error.headers.get('Date');
return (<react_native_1.View style={{
padding: 12,
gap: 8,
}}>
<react_native_1.Text selectable allowFontScaling style={{
fontSize: react_native_1.Platform.select({ web: 24, default: 16 }),
fontWeight: 'bold',
marginBottom: 4,
color: 'white',
}}>
{title}
</react_native_1.Text>
{process.env.EXPO_OS === 'web' ? (<react_native_1.ScrollView style={{
borderColor: 'rgba(255,255,255,0.5)',
borderTopWidth: react_native_1.StyleSheet.hairlineWidth,
borderBottomWidth: react_native_1.StyleSheet.hairlineWidth,
maxHeight: 150,
}} contentContainerStyle={{ paddingVertical: 4 }}>
<react_native_1.Text testID="router_error_message" selectable allowFontScaling style={{
color: 'white',
}}>
{error.message}
</react_native_1.Text>
</react_native_1.ScrollView>) : (<react_native_1.TextInput testID="router_error_message" scrollEnabled multiline editable={false} allowFontScaling value={error.message} style={{
borderColor: 'rgba(255,255,255,0.5)',
borderTopWidth: react_native_1.StyleSheet.hairlineWidth,
borderBottomWidth: react_native_1.StyleSheet.hairlineWidth,
paddingVertical: 4,
maxHeight: 150,
color: 'white',
}}/>)}
<InfoRow title="Code" right={error.statusCode}/>
{errorId && <InfoRow title="ID" right={errorId}/>}
{date && <InfoRow title="Date" right={date}/>}
{error.url && (<react_native_1.Text selectable allowFontScaling style={{ fontSize: 14, opacity: 0.5, color: 'white' }}>
{error.url}
</react_native_1.Text>)}
</react_native_1.View>);
}
function InfoRow({ title, right }) {
const style = {
fontSize: 16,
color: 'white',
};
return (<react_native_1.View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<react_native_1.Text selectable allowFontScaling style={style}>
{title}
</react_native_1.Text>
{right && (<react_native_1.Text selectable allowFontScaling style={[style, styles.code]}>
{right}
</react_native_1.Text>)}
</react_native_1.View>);
}
const styles = react_native_1.StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'black',
padding: 24,
alignItems: 'stretch',
justifyContent: 'center',
},
title: {
color: 'white',
fontSize: react_native_1.Platform.select({ web: 32, default: 24 }),
fontWeight: 'bold',
},
buttonText: {
fontSize: 18,
fontWeight: 'bold',
color: 'black',
...react_native_1.Platform.select({
web: {
transitionDuration: '100ms',
},
}),
},
buttonInner: {
...react_native_1.Platform.select({
web: {
transitionDuration: '100ms',
},
}),
paddingVertical: 12,
paddingHorizontal: 24,
borderColor: 'white',
borderWidth: 2,
marginLeft: 8,
justifyContent: 'center',
alignItems: 'center',
},
code: {
fontFamily: react_native_1.Platform.select({
default: 'Courier',
ios: 'Courier New',
android: 'monospace',
}),
fontWeight: '500',
},
errorMessage: {
color: 'white',
fontSize: 16,
},
subtitle: {
color: 'white',
fontSize: 14,
marginBottom: 12,
},
link: {
color: 'rgba(255,255,255,0.4)',
textDecorationStyle: 'solid',
textDecorationLine: 'underline',
fontSize: 14,
textAlign: 'center',
},
});
//# sourceMappingURL=ErrorBoundary.js.map
;