expo-router
Version:
Expo Router is a file-based router for React Native and web applications.
231 lines (230 loc) • 8.87 kB
JavaScript
// Copyright © 2024 650 Industries.
'use client';
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sitemap = exports.getNavOptions = void 0;
const react_1 = __importDefault(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 router_store_1 = require("../global-state/router-store");
const imperative_api_1 = require("../imperative-api");
const Link_1 = require("../link/Link");
const matchers_1 = require("../matchers");
const statusbar_1 = require("../utils/statusbar");
const INDENT = 20;
function getNavOptions() {
return {
title: 'sitemap',
presentation: 'modal',
headerLargeTitle: false,
headerTitleStyle: {
color: 'white',
},
headerTintColor: 'white',
headerLargeTitleStyle: {
color: 'white',
},
headerStyle: {
backgroundColor: 'black',
// @ts-expect-error: mistyped
borderBottomColor: '#323232',
},
header: () => {
const WrapperElement = react_native_1.Platform.OS === 'android' ? react_native_safe_area_context_1.SafeAreaView : react_native_1.View;
return (<WrapperElement style={styles.header}>
<react_native_1.View style={styles.headerContent}>
<react_native_1.View style={styles.headerIcon}>
<SitemapIcon />
</react_native_1.View>
<react_native_1.Text role="heading" aria-level={1} style={styles.title}>
Sitemap
</react_native_1.Text>
</react_native_1.View>
</WrapperElement>);
},
};
}
exports.getNavOptions = getNavOptions;
function Sitemap() {
return (<react_native_1.View style={styles.container}>
{statusbar_1.canOverrideStatusBarBehavior && <react_native_1.StatusBar barStyle="light-content"/>}
<react_native_1.ScrollView contentContainerStyle={styles.scroll}>
<FileSystemView />
</react_native_1.ScrollView>
</react_native_1.View>);
}
exports.Sitemap = Sitemap;
function FileSystemView() {
const routes = (0, router_store_1.useExpoRouter)().getSortedRoutes();
return routes.map((route) => (<react_native_1.View key={route.contextKey} style={styles.itemContainer}>
<FileItem route={route}/>
</react_native_1.View>));
}
function FileItem({ route, level = 0, parents = [], isInitial = false, }) {
const disabled = route.children.length > 0;
const segments = react_1.default.useMemo(() => [...parents, ...route.route.split('/')], [parents, route.route]);
const href = react_1.default.useMemo(() => {
return ('/' +
segments
.map((segment) => {
// add an extra layer of entropy to the url for deep dynamic routes
if ((0, matchers_1.matchDeepDynamicRouteName)(segment)) {
return segment + '/' + Date.now();
}
// index must be erased but groups can be preserved.
return segment === 'index' ? '' : segment;
})
.filter(Boolean)
.join('/'));
}, [segments, route.route]);
const filename = react_1.default.useMemo(() => {
const segments = route.contextKey.split('/');
// join last two segments for layout routes
if (route.contextKey.match(/_layout\.[jt]sx?$/)) {
return segments[segments.length - 2] + '/' + segments[segments.length - 1];
}
const routeSegmentsCount = route.route.split('/').length;
// Join the segment count in reverse order
// This presents files without layout routes as children with all relevant segments.
return segments.slice(-routeSegmentsCount).join('/');
}, [route]);
const info = isInitial ? 'Initial' : route.generated ? 'Virtual' : '';
return (<>
{!route.internal && (<Link_1.Link accessibilityLabel={route.contextKey} href={href} onPress={() => {
if (react_native_1.Platform.OS !== 'web' && imperative_api_1.router.canGoBack()) {
// Ensure the modal pops
imperative_api_1.router.back();
}
}} disabled={disabled} asChild
// Ensure we replace the history so you can't go back to this page.
replace>
<Pressable_1.Pressable>
{({ pressed, hovered }) => (<react_native_1.View style={[
styles.itemPressable,
{
paddingLeft: INDENT + level * INDENT,
backgroundColor: hovered ? '#202425' : 'transparent',
},
pressed && { backgroundColor: '#26292b' },
disabled && { opacity: 0.4 },
]}>
<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center' }}>
{route.children.length ? <PkgIcon /> : <FileIcon />}
<react_native_1.Text style={styles.filename}>{filename}</react_native_1.Text>
</react_native_1.View>
<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center' }}>
{!!info && (<react_native_1.Text style={[styles.virtual, !disabled && { marginRight: 8 }]}>{info}</react_native_1.Text>)}
{!disabled && <ForwardIcon />}
</react_native_1.View>
</react_native_1.View>)}
</Pressable_1.Pressable>
</Link_1.Link>)}
{route.children.map((child) => (<FileItem key={child.contextKey} route={child} isInitial={route.initialRouteName === child.route} parents={segments} level={level + (route.generated ? 0 : 1)}/>))}
</>);
}
function FileIcon() {
return <react_native_1.Image style={styles.image} source={require('expo-router/assets/file.png')}/>;
}
function PkgIcon() {
return <react_native_1.Image style={styles.image} source={require('expo-router/assets/pkg.png')}/>;
}
function ForwardIcon() {
return <react_native_1.Image style={styles.image} source={require('expo-router/assets/forward.png')}/>;
}
function SitemapIcon() {
return <react_native_1.Image style={styles.image} source={require('expo-router/assets/sitemap.png')}/>;
}
const styles = react_native_1.StyleSheet.create({
container: {
backgroundColor: 'black',
flex: 1,
alignItems: 'stretch',
},
header: {
backgroundColor: '#151718',
paddingVertical: 16,
borderBottomWidth: 1,
borderColor: '#313538',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.33,
shadowRadius: 3,
elevation: 8,
},
headerContent: {
flexDirection: 'row',
alignItems: 'center',
gap: 14,
paddingHorizontal: '5%',
...react_native_1.Platform.select({
web: {
width: '100%',
maxWidth: 960,
marginHorizontal: 'auto',
},
}),
},
title: {
color: 'white',
fontSize: 28,
fontWeight: 'bold',
},
scroll: {
paddingHorizontal: '5%',
paddingVertical: 16,
...react_native_1.Platform.select({
ios: {
paddingBottom: 24,
},
web: {
width: '100%',
maxWidth: 960,
marginHorizontal: 'auto',
paddingBottom: 24,
},
default: {
paddingBottom: 12,
},
}),
},
itemContainer: {
borderWidth: 1,
borderColor: '#313538',
backgroundColor: '#151718',
borderRadius: 12,
marginBottom: 12,
overflow: 'hidden',
},
itemPressable: {
paddingHorizontal: INDENT,
paddingVertical: 16,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
...react_native_1.Platform.select({
web: {
transitionDuration: '100ms',
},
}),
},
filename: { color: 'white', fontSize: 20, marginLeft: 12 },
virtual: { textAlign: 'right', color: 'white' },
image: { width: 24, height: 24, resizeMode: 'contain', opacity: 0.6 },
headerIcon: {
width: 40,
height: 40,
backgroundColor: '#202425',
borderRadius: 8,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
});
//# sourceMappingURL=Sitemap.js.map