Skip to content

Commit 37ff001

Browse files
ImLunaHeyclaude
andcommitted
fix(expo-router): pickDefaultScreen prefers a group with an index leaf
When the user-driven redirect after sign-in landed on the root with href '/', our Stack matched the empty segment, fell back to \`screens[0]\` — which is the FIRST <Stack.Screen> declared in akari's root layout: '(auth)'. Effect: every successful login bounced the user right back to the auth choice screen. Real expo-router treats group segments \`(name)\` as URL-transparent: '/' resolves through whatever group has an 'index' leaf. For akari that's '(tabs)' (\`app/(tabs)/index/index.tsx\`), not '(auth)' (which only has signin/oauth/password siblings, no index). Add pickDefaultScreen(screens, base): walks the screens, picks the first group whose corresponding file-system route table entry has an index child (\`<group>/index\`, \`<group>/index/_layout\`, or \`<group>/index/index\`). Falls back to \`screens[0]\` when no group match — keeps existing apps (smoke-demo, expo-router-tabs.tsx, etc.) unchanged, since they have no route table registered. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9952b50 commit 37ff001

1 file changed

Lines changed: 29 additions & 2 deletions

File tree

packages/@lucid-softworks/react-native-linux-expo/expo-router.js

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,33 @@ function effectiveSegment(pathname, base) {
209209
return p.split('/')[0] || '';
210210
}
211211

212+
// When the pathname doesn't pick a screen by name (typically because
213+
// the user just navigated to `/` and the layout has only group screens
214+
// like `(auth)` / `(tabs)`), pick the one whose group has an `index`
215+
// route in our file-system table. Real expo-router treats group
216+
// segments as URL-transparent — `/` resolves through the group that
217+
// has an index leaf. For akari that's `(tabs)` (it has
218+
// `app/(tabs)/index/index.tsx`), NOT `(auth)`. Without this lookup we
219+
// always fall back to `screens[0]`, which kept routing post-login
220+
// back to the auth choice screen.
221+
function pickDefaultScreen(screens, base) {
222+
const routes = typeof globalThis !== 'undefined' ? globalThis.__expoRouterRoutes : null;
223+
if (routes) {
224+
for (const s of screens) {
225+
if (!s.name || s.name[0] !== '(' || s.name[s.name.length - 1] !== ')') continue;
226+
const groupPath = (base ? base : '') + '/' + s.name;
227+
if (
228+
routes[groupPath + '/index'] ||
229+
routes[groupPath + '/index/_layout'] ||
230+
routes[groupPath + '/index/index']
231+
) {
232+
return s;
233+
}
234+
}
235+
}
236+
return screens[0];
237+
}
238+
212239
// ────────────────────────────────────────────────────────────────
213240
// Stack — renders the screen whose `name` matches the current
214241
// pathname segment. Stack.Screen is config-only (no own render).
@@ -222,7 +249,7 @@ function Stack({children, screenOptions}) {
222249
const base = React.useContext(RouteBaseContext);
223250
const screens = collectScreens(children, Stack.Screen, base);
224251
const seg = effectiveSegment(ctx.pathname, base) || 'index';
225-
const match = screens.find(s => s.name === seg) ?? screens[0];
252+
const match = screens.find(s => s.name === seg) ?? pickDefaultScreen(screens, base);
226253
const headerShown = match?.options?.headerShown ?? screenOptions?.headerShown ?? true;
227254
const tree = React.createElement(
228255
View,
@@ -264,7 +291,7 @@ function Tabs({children, screenOptions}) {
264291
const base = React.useContext(RouteBaseContext);
265292
const screens = collectScreens(children, Tabs.Screen, base);
266293
const seg = effectiveSegment(ctx.pathname, base) || screens[0]?.name;
267-
const active = screens.find(s => s.name === seg) ?? screens[0];
294+
const active = screens.find(s => s.name === seg) ?? pickDefaultScreen(screens, base);
268295
const activeColor =
269296
active?.options?.tabBarActiveTintColor ?? screenOptions?.tabBarActiveTintColor ?? '#2563eb';
270297
const inactiveColor =

0 commit comments

Comments
 (0)