Layouts and Nested Navigators

Layouts nest the way folders do. BookNest's root layout is a stack whose first screen is the whole (tabs) group, so the tab navigator lives inside the stack. The file's default export wraps this stack in SessionProvider and a StatusBar: the root layout is where app-wide providers go, since every screen renders inside it.

src/app/_layout.tsx: the root stack, with the tabs as its first screen (excerpt)TSX
function RootStack() {
  const { user } = useSession();
  const path = usePathname();
  useEffect(() => console.log('path:', path), [path]);
  return (
    <Stack screenOptions={{ headerTintColor: '#1565c0' }}>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen name="book/[id]" options={{ title: '' }} />
      <Stack.Screen name="notes/[id]"
        options={{ presentation: 'modal', title: 'Reading notes' }} />
      <Stack.Protected guard={user !== null}>
        <Stack.Screen name="checkout" options={{ title: 'Checkout' }} />
      </Stack.Protected>
      <Stack.Screen name="sign-in" options={{ title: 'Sign in' }} />
    </Stack>
  );
}

Where a screen sits decides what surrounds it. book/[id] belongs to the root stack, so it covers the tab bar; inside (tabs), under a stack layout of its own, it would keep the tab bar visible. The (tabs) screen hides the stack's header because the tabs draw their own. presentation: 'modal' makes reading notes a sheet on iOS; on Android it is a full screen, as the emulator showed.

A navigator's options reach its direct children only: headerTintColor here does not color the tab headers. And a linked screen needs something underneath it. Cold-starting BookNest from booknest://book/3 and pressing Back left the app. One more line in the root layout, export const unstable_settings = { anchor: '(tabs)' };, names the screen the router places at the bottom of the stack (anchor replaced the deprecated initialRouteName). With it, the same test logged path: / after Back and showed the catalog.