📁 File path: apps/weshipit/pages/plan/2026-W28.md

React Native Roadmap 2026-W28

Week of July 6–July 12, 2026

Items This Week

#TitleLabelLink
1Zoomable Calendar Grids, On-Device Gemini Nano & Astryx Design System🟦 RNRead
2Sign in with Passkeys — Expo🟧 EXPORead
3A Hell of a Time to Be a Builder🟧 EXPORead
4React Status #482 — TypeScript 7.0 & React Navigation 8⚛️ REACTRead
5Nesting Tabs and Drawers with Expo Router🟧 EXPORead
6@react-native-ai/adk — On-Device Android AI via Google ADK🟦 RNRead
7Maestro MCP — Let Your Agent Test the App It Just Built🟦 RNRead

5-Day Action Plan


🟦 Chunk 1 — Implement a Gesture-Driven Calendar with super-calendar

Goal: Add a fully interactive, pinch-to-zoom month/week/day calendar to your React Native app using super-calendar, backed by Reanimated shared values and Legend List virtualisation — so the UI thread never drops a frame while navigating months or dragging events.

Scope:

  • Install super-calendar and its peer deps (react-native-reanimated, react-native-gesture-handler, @legendapp/list)
  • Replace or supplement an existing date picker / flat calendar view with <Calendar />
  • Configure onDragEvent, onResizeEvent, and onCreateEvent callbacks
  • Wire event data from local state or an API
  • Use the onDragEvent veto pattern (return false) to lock read-only events

Out of scope: Server-side event persistence, push notification reminders, recurring event recurrence rules, web support.

Dependencies: React Native ≥ 0.73, Reanimated ≥ 3, Gesture Handler ≥ 2. Worklet runtime enabled.

Acceptance criteria:

  • Pinch gesture zooms the week/day grid smoothly at 60 fps with no React re-renders visible in Profiler
  • Long-press + drag moves a mutable event; dragging a locked event snaps it back
  • Month view virtualises correctly — scrolling 12 months back/forward stays under 16 ms frame time
  • Calendar renders correctly in both light and dark mode

Estimated effort: M

**Copy/paste this prompt:**

Implement the following React Native chunk for your mobile app: Integrate a gesture-driven calendar using super-calendar.

Goal: Add a pinch-to-zoom, gesture-driven month/week/day calendar backed by Reanimated shared values. Zero re-renders during zoom animations.

Files to create/modify:

  • src/components/Calendar/AppCalendar.tsx — new wrapper component
  • src/screens/CalendarScreen.tsx — consume <AppCalendar />
  • package.json — add super-calendar, ensure react-native-reanimated and react-native-gesture-handler are present

Step-by-step:

  1. npm install super-calendar (check peer deps and install any missing ones).
  2. Wrap your app entry with <GestureHandlerRootView> if not already done.
  3. Create AppCalendar.tsx that renders <Calendar mode="week" /> from super-calendar.
  4. Pass an events array of { id, title, start, end, color } objects.
  5. Implement onDragEvent={(event) => { if (event.id === 'locked') return false; updateEvent(event); }}.
  6. Implement onResizeEvent and onCreateEvent callbacks.
  7. Enable the pinch gesture: it is on by default — verify it works on a physical device.
  8. Confirm with React DevTools Profiler that no React re-renders fire during a pinch gesture.

Acceptance criteria checklist:

  • Pinch gesture zooms week grid at 60 fps on a mid-range device
  • Dragging an event updates state correctly
  • Dragging a locked event returns it to its original position
  • Navigating 12 months via swipe stays under 16 ms frame time in Profiler
  • No Metro bundler errors on both iOS and Android

🟧 Chunk 2 — Implement Nested Drawer + Bottom Tabs with Expo Router

Goal: Build a production-grade hybrid navigation layout where a drawer navigator wraps bottom tabs in Expo Router using the file-system routing convention — giving users swipe-from-left access to global sections while keeping tab navigation for primary flows.

Scope:

  • Create a (drawer) layout group in app/ containing a (tabs) nested group
  • Configure <Drawer> with themed header and gesture handling
  • Configure <Tabs> with icons and themed tab bar inside the drawer
  • Handle dark/light mode theming for both navigators consistently
  • Verify swipe-to-open drawer gesture does not conflict with horizontal tab swipes

Out of scope: Deep linking configuration, authentication guards, animations beyond defaults, web routing support.

Dependencies: Expo SDK 57, expo-router ≥ 4, @react-navigation/drawer, react-native-gesture-handler, react-native-reanimated.

Acceptance criteria:

  • Swiping from the left edge opens the drawer without triggering a tab swipe
  • Navigating between tabs does not close the drawer unexpectedly
  • Drawer and tab bar adapt correctly to system light/dark mode
  • Deep navigation state is preserved when the drawer is toggled
  • No TypeScript errors from route types

Estimated effort: S

**Copy/paste this prompt:**

Implement the following React Native chunk for your mobile app: Nested drawer + bottom tabs navigation with Expo Router file-system conventions.

Goal: Create a (drawer)/(tabs) layout where a swipeable drawer wraps themed bottom tabs, following Expo Router's file-system routing pattern.

Files to create/modify:

  • app/(drawer)/_layout.tsx — Drawer layout
  • app/(drawer)/(tabs)/_layout.tsx — Tabs layout nested inside drawer
  • app/(drawer)/(tabs)/index.tsx — Home tab screen
  • app/(drawer)/(tabs)/explore.tsx — Second tab screen
  • app/(drawer)/settings.tsx — Drawer-only screen (not a tab)
  • package.json — ensure @react-navigation/drawer, react-native-gesture-handler, react-native-reanimated are installed

Step-by-step:

  1. Install dependencies: npx expo install @react-navigation/drawer react-native-gesture-handler react-native-reanimated.
  2. Create app/(drawer)/_layout.tsx:
    import { Drawer } from 'expo-router/drawer';
    export default function DrawerLayout() {
      return <Drawer screenOptions={{ headerShown: false }} />;
    }
    
  3. Create app/(drawer)/(tabs)/_layout.tsx:
    import { Tabs } from 'expo-router';
    export default function TabsLayout() {
      return (
        <Tabs screenOptions={{ tabBarActiveTintColor: '#6200ee' }}>
          <Tabs.Screen name="index" options={{ title: 'Home' }} />
          <Tabs.Screen name="explore" options={{ title: 'Explore' }} />
        </Tabs>
      );
    }
    
  4. Add app/(drawer)/settings.tsx as a drawer-only route.
  5. Verify gesture handler root view is at the app root (app/_layout.tsx).
  6. Test on a physical iOS and Android device: swipe from left to open drawer, swipe horizontally on tabs.
  7. Enable dark mode on the device and confirm both navigators update their theme.

Acceptance criteria checklist:

  • Left swipe opens drawer; tab swipe only activates when not near the left edge
  • Tabs render correctly with icons and active color
  • Settings screen reachable from drawer but absent from tab bar
  • Dark mode applied consistently across drawer header and tab bar
  • No TypeScript route type errors (expo-router typed routes enabled)

🟦 Chunk 3 — Configure Maestro MCP for AI-Driven E2E Testing

Goal: Connect Claude Code (or another coding agent) to a live iOS simulator or Android emulator via Maestro MCP so the agent can autonomously run, screenshot, and verify flows — and save the resulting YAML as a repeatable regression test.

Scope:

  • Install Maestro CLI (curl -Ls "https://get.maestro.mobile.dev" | bash)
  • Add Maestro MCP to Claude Code: claude mcp add maestro -- maestro mcp
  • Write a first E2E flow (login screen → home tab) in YAML
  • Trigger the flow from within a Claude Code session via the MCP tool
  • Capture and save a screenshot assertion

Out of scope: CI/CD integration (GitHub Actions), multi-device parallel runs, performance benchmarking, Appium or Detox migration.

Dependencies: Maestro CLI installed locally, iOS Simulator or Android Emulator running, Claude Code ≥ 1.0 (or any MCP-compatible agent).

Acceptance criteria:

  • maestro mcp starts without errors and the MCP server is listed in Claude Code
  • Agent can describe the screen hierarchy by calling the MCP tool
  • Agent taps the login button and verifies the home screen appears via screenshot
  • The generated YAML flow can be replayed with maestro test login.yaml independently
  • Test pass/fail result is reported back to the agent session

Estimated effort: S

**Copy/paste this prompt:**

Implement the following React Native chunk for your mobile app: Configure Maestro MCP so a Claude Code agent can drive and test your app on a live device.

Goal: Give your AI coding agent eyes and hands on the running app — letting it tap, verify screens, and save repeatable E2E tests — using Maestro MCP.

Files to create/modify:

  • .maestro/login.yaml — first E2E test flow
  • package.json (optionally) — add a "test:e2e" script

Step-by-step:

  1. Install Maestro: curl -Ls "https://get.maestro.mobile.dev" | bash and verify with maestro --version.
  2. Start your app on an iOS Simulator or Android Emulator.
  3. Run maestro studio to inspect the view hierarchy and find element IDs/text for your login screen.
  4. Create .maestro/login.yaml:
    appId: com.yourapp.bundle
    ---
    - launchApp
    - tapOn: 'Email'
    - inputText: 'test@example.com'
    - tapOn: 'Password'
    - inputText: 'password123'
    - tapOn: 'Sign In'
    - assertVisible: 'Welcome'
    - takeScreenshot: login-success
    
  5. Run maestro test .maestro/login.yaml and confirm it passes.
  6. Add Maestro MCP to Claude Code: claude mcp add maestro -- maestro mcp.
  7. In a Claude Code session, ask: "Run the Maestro login flow and tell me what you see on screen."
  8. Confirm the agent calls the MCP tool, drives the simulator, and reports back.

Acceptance criteria checklist:

  • maestro test .maestro/login.yaml passes end-to-end without manual intervention
  • maestro mcp server appears in Claude Code MCP list
  • Agent can read the screen hierarchy via MCP and identify UI elements
  • Agent-triggered flow produces a screenshot saved to the Maestro output folder
  • YAML flow is committed to version control for future CI use

🟦 Chunk 4 — Integrate @react-native-ai/adk for On-Device Android AI

Goal: Implement an on-device AI feature on Android — such as a smart reply, image description, or chat assistant — using @react-native-ai/adk, which wraps Google's Agent Development Kit as a Vercel AI SDK provider, keeping inference fully local with no cloud round-trips.

Scope:

  • Install @react-native-ai/adk and the Vercel AI SDK (ai package)
  • Configure the ADK provider pointing to an on-device Gemini Nano model
  • Build a simple UI: a text input + response display using useChat from the ai package
  • Handle streaming output and display tokens progressively
  • Add a loading state and an error boundary

Out of scope: iOS Foundation Models integration (separate package), cloud fallback logic, multi-turn tool calling, model fine-tuning.

Dependencies: Android device with Gemini Nano support (Pixel 6+ or equivalent), @react-native-ai/adk ≥ 0.1, Vercel AI SDK (ai ≥ 4.0), React Native 0.76+.

Acceptance criteria:

  • The AI feature works fully offline (airplane mode enabled during test)
  • First token appears within 2 seconds of submitting a prompt
  • Streaming text renders progressively without layout jank
  • Error state shows a user-friendly message if the model is unavailable
  • No network requests made during inference (verified in DevTools network tab)

Estimated effort: M

**Copy/paste this prompt:**

Implement the following React Native chunk for your mobile app: Add on-device Android AI using @react-native-ai/adk and the Vercel AI SDK.

Goal: Build a local AI chat feature on Android that uses Gemini Nano on-device via Google's ADK, wrapped as a Vercel AI SDK provider — no internet connection required during inference.

Files to create/modify:

  • src/ai/adk-provider.ts — configure the ADK provider
  • src/screens/OnDeviceAIScreen.tsx — chat UI using useChat
  • package.json — add @react-native-ai/adk and ai

Step-by-step:

  1. Install: npm install @react-native-ai/adk ai.

  2. Create src/ai/adk-provider.ts:

    import { createADK } from '@react-native-ai/adk';
    export const adk = createADK();
    export const model = adk('gemini-nano');
    
  3. Create OnDeviceAIScreen.tsx using the useChat hook:

    import { useChat } from 'ai/react';
    import { model } from '../ai/adk-provider';
    
    export default function OnDeviceAIScreen() {
      const { messages, input, handleInputChange, handleSubmit } = useChat({ model });
      return (
        <View>
          <FlatList data={messages} renderItem={({ item }) => <Text>{item.content}</Text>} />
          <TextInput value={input} onChangeText={handleInputChange} />
          <Button title="Send" onPress={handleSubmit} />
        </View>
      );
    }
    
  4. Enable airplane mode on the Android device.

  5. Run the app, type a prompt, and verify inference completes locally.

  6. Add a loading indicator while the model is generating.

  7. Add an error boundary that catches ModelUnavailableError from the ADK.

Acceptance criteria checklist:

  • App builds and runs on Android without native compilation errors
  • Inference works with airplane mode enabled (fully offline)
  • First token appears within 2 seconds on a Pixel 6+
  • Text streams progressively as tokens are generated
  • Error boundary shows a friendly message if model is not available on device

⚛️ Chunk 5 — Upgrade to TypeScript 7.0 for 10× Faster Type-Checking

Goal: Migrate the project's TypeScript compiler to version 7.0 (the Go-powered tsc) to dramatically reduce type-check time in CI and local development — while keeping the existing TS 6.x programmatic API for tools that depend on it (e.g. ts-jest, ESLint plugins).

Scope:

  • Update typescript to ^7.0 in package.json
  • Verify tsconfig.json compatibility (no removed options)
  • Run tsc --noEmit with the new compiler and fix any new stricter errors
  • Update CI type-check step to use tsc directly (not via a wrapper that requires the programmatic API)
  • Benchmark build time before/after and document the speedup

Out of scope: Migrating Jest transformer from ts-jest to a native alternative (programmatic API not yet in TS 7), enabling new TS 7 language features, full ESLint TypeScript plugin upgrade.

Dependencies: TypeScript ≥ 7.0, Node.js ≥ 20, no tooling that relies on tsc programmatic API in CI.

Acceptance criteria:

  • npx tsc --noEmit completes without errors using TypeScript 7.0
  • CI type-check job is at least 3× faster than the TS 6.x baseline (measured in seconds)
  • No new type errors introduced (or all new errors are fixed)
  • Existing tooling (Metro, Expo, ESLint) still works correctly with the new compiler
  • package.json typescript version is pinned to ^7.0

Estimated effort: S

**Copy/paste this prompt:**

Implement the following React Native chunk for your mobile app: Upgrade TypeScript to version 7.0 for 10× faster type-checking.

Goal: Replace the TypeScript 6.x compiler with the new Go-powered TypeScript 7.0 to slash type-check times in local dev and CI, without breaking Expo or Metro tooling.

Files to create/modify:

  • package.json — bump typescript to ^7.0
  • tsconfig.json — remove any options deprecated or removed in TS 7
  • .github/workflows/ci.yml (or equivalent) — update type-check step

Step-by-step:

  1. Record baseline: time npx tsc --noEmit with current TypeScript version.
  2. Run npm install typescript@^7.0 --save-dev.
  3. Run npx tsc --noEmit and review any new errors carefully.
  4. Fix strict errors: TS 7 tightens inference in some edge cases — address each error in the codebase.
  5. Check tsconfig.json for any removed compiler options (e.g. importsNotUsedAsValues was removed in 5.5+).
  6. Verify Metro bundler starts: npx expo start and check for TypeScript-related warnings.
  7. Verify ESLint TypeScript plugin works: npx eslint . --ext .ts,.tsx.
  8. Update CI workflow to run tsc --noEmit directly (not via ts-jest or ts-node, which need the programmatic API).
  9. Record new time: time npx tsc --noEmit — document the speedup in a comment in tsconfig.json.

Acceptance criteria checklist:

  • npm install succeeds with typescript@^7.0
  • npx tsc --noEmit exits 0 with no errors
  • Type-check time is reduced by ≥ 3× vs TS 6 baseline
  • npx expo start launches without TypeScript-related errors
  • ESLint with @typescript-eslint runs without crashing
  • CI pipeline passes on the updated workflow